Skip to content

Commit ae02290

Browse files
Identify layer features Sample (#140)
Co-authored-by: Shubham Sharma <[email protected]>
1 parent 24d6391 commit ae02290

26 files changed

+760
-0
lines changed

identify-layer-features/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

identify-layer-features/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Identify layer features
2+
3+
Identify features in all layers in a map.
4+
5+
![Image of identify layers](identify-layer-features.png)
6+
7+
## Use case
8+
9+
"Identify layers" operation allows users to tap on a map, returning features at that location across multiple layers. Because some layer types have sublayers, the sample recursively counts results for sublayers within each layer.
10+
11+
## How to use the sample
12+
13+
Tap to identify features. A bottom text banner will show all layers with features under the tapped location, as well as the number of features.
14+
15+
## How it works
16+
17+
1. The tapped position is passed to `MapView.identifyLayers(...)` method.
18+
2. For each `IdentifyLayerResult` in the results, features are counted.
19+
* Note: there is one identify result per layer with matching features; if the feature count is 0, that means a sublayer contains the matching features.
20+
21+
## Relevant API
22+
23+
* IdentifyLayerResult
24+
* IdentifyLayerResult.sublayerResults
25+
* LayerContent
26+
27+
## Additional information
28+
29+
The GeoView supports two methods of identify: `identifyLayer`, which identifies features within a specific layer and `identifyLayers`, which identifies features for all layers in the current view.
30+
31+
## Tags
32+
33+
identify, recursion, recursive, sublayers
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"category": "Search and Query",
3+
"description": "Identify features in all layers in a map.",
4+
"formal_name": "IdentifyLayerFeatures",
5+
"ignore": false,
6+
"images": [
7+
"identify-layer-features.png"
8+
],
9+
"keywords": [
10+
"identify",
11+
"recursion",
12+
"recursive",
13+
"sublayers",
14+
"IdentifyLayerResult",
15+
"IdentifyLayerResult.sublayerResults",
16+
"LayerContent"
17+
],
18+
"language": "kotlin",
19+
"redirect_from": "",
20+
"relevant_apis": [
21+
"IdentifyLayerResult",
22+
"IdentifyLayerResult.sublayerResults",
23+
"LayerContent"
24+
],
25+
"snippets": [
26+
"src/main/java/com/esri/arcgismaps/sample/identifylayerfeatures/MainActivity.kt",
27+
"src/main/java/com/esri/arcgismaps/sample/identifylayerfeatures/components/ComposeMapView.kt",
28+
"src/main/java/com/esri/arcgismaps/sample/identifylayerfeatures/components/MapViewModel.kt",
29+
"src/main/java/com/esri/arcgismaps/sample/identifylayerfeatures/screens/MainScreen.kt"
30+
],
31+
"title": "Identify layer features"
32+
}

identify-layer-features/build.gradle

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
apply plugin: 'com.android.application'
2+
apply plugin: 'org.jetbrains.kotlin.android'
3+
4+
android {
5+
compileSdkVersion rootProject.ext.compileSdkVersion
6+
7+
defaultConfig {
8+
applicationId "com.esri.arcgismaps.sample.identifylayerfeatures"
9+
minSdkVersion rootProject.ext.minSdkVersion
10+
targetSdkVersion rootProject.ext.targetSdkVersion
11+
versionCode rootProject.ext.versionCode
12+
versionName rootProject.ext.versionName
13+
buildConfigField("String", "API_KEY", API_KEY)
14+
}
15+
16+
buildTypes {
17+
release {
18+
minifyEnabled false
19+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20+
}
21+
}
22+
23+
buildFeatures {
24+
compose = true
25+
buildConfig = true
26+
}
27+
composeOptions {
28+
kotlinCompilerExtensionVersion = "$kotlinCompilerExt"
29+
}
30+
31+
namespace 'com.esri.arcgismaps.sample.identifylayerfeatures'
32+
}
33+
34+
dependencies {
35+
// lib dependencies from rootProject build.gradle
36+
implementation "androidx.core:core-ktx:$ktxAndroidCore"
37+
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$ktxLifecycle"
38+
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$ktxLifecycle"
39+
implementation "androidx.activity:activity-compose:$composeActivityVersion"
40+
// Jetpack Compose Bill of Materials
41+
implementation platform("androidx.compose:compose-bom:$composeBOM")
42+
// Jetpack Compose dependencies
43+
implementation "androidx.compose.ui:ui"
44+
implementation "androidx.compose.material3:material3"
45+
implementation "androidx.compose.ui:ui-tooling"
46+
implementation "androidx.compose.ui:ui-tooling-preview"
47+
implementation project(path: ':samples-lib')
48+
}
Loading
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3+
4+
<uses-permission android:name="android.permission.INTERNET" />
5+
6+
<application
7+
android:allowBackup="true"
8+
android:icon="@mipmap/ic_launcher"
9+
android:label="@string/app_name"
10+
android:roundIcon="@mipmap/ic_launcher_round"
11+
android:supportsRtl="true"
12+
android:theme="@style/AppTheme">
13+
<activity
14+
android:exported="true"
15+
android:name=".MainActivity">
16+
<intent-filter>
17+
<action android:name="android.intent.action.MAIN" />
18+
19+
<category android:name="android.intent.category.LAUNCHER" />
20+
</intent-filter>
21+
</activity>
22+
</application>
23+
24+
</manifest>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* Copyright 2023 Esri
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*
15+
*/
16+
17+
package com.esri.arcgismaps.sample.identifylayerfeatures
18+
19+
import android.os.Bundle
20+
import androidx.activity.ComponentActivity
21+
import androidx.activity.compose.setContent
22+
import androidx.compose.material3.MaterialTheme
23+
import androidx.compose.material3.Surface
24+
import androidx.compose.runtime.Composable
25+
import com.arcgismaps.ApiKey
26+
import com.arcgismaps.ArcGISEnvironment
27+
import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme
28+
import com.esri.arcgismaps.sample.identifylayerfeatures.screens.MainScreen
29+
30+
class MainActivity : ComponentActivity() {
31+
32+
override fun onCreate(savedInstanceState: Bundle?) {
33+
super.onCreate(savedInstanceState)
34+
// authentication with an API key or named user is
35+
// required to access basemaps and other location services
36+
ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.API_KEY)
37+
38+
setContent {
39+
SampleAppTheme {
40+
IdentifyLayerFeaturesApp()
41+
}
42+
}
43+
}
44+
45+
@Composable
46+
private fun IdentifyLayerFeaturesApp() {
47+
Surface(
48+
color = MaterialTheme.colorScheme.background
49+
) {
50+
MainScreen(
51+
sampleName = getString(R.string.app_name),
52+
application = application
53+
)
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* Copyright 2023 Esri
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*
15+
*/
16+
17+
package com.esri.arcgismaps.sample.identifylayerfeatures.components
18+
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.runtime.DisposableEffect
21+
import androidx.compose.runtime.LaunchedEffect
22+
import androidx.compose.runtime.collectAsState
23+
import androidx.compose.runtime.getValue
24+
import androidx.compose.ui.Modifier
25+
import androidx.compose.ui.platform.LocalContext
26+
import androidx.compose.ui.platform.LocalLifecycleOwner
27+
import androidx.compose.ui.viewinterop.AndroidView
28+
import androidx.lifecycle.LifecycleOwner
29+
import com.arcgismaps.mapping.view.MapView
30+
31+
/**
32+
* Wraps the MapView in a Composable function.
33+
*/
34+
@Composable
35+
fun ComposeMapView(
36+
modifier: Modifier = Modifier,
37+
mapViewModel: MapViewModel
38+
) {
39+
// get an instance of the current lifecycle owner
40+
val lifecycleOwner = LocalLifecycleOwner.current
41+
// collect the latest state of the MapViewState
42+
val mapViewState by mapViewModel.mapViewState.collectAsState()
43+
// create and add MapView to the activity lifecycle
44+
val mapView = createMapViewInstance(lifecycleOwner)
45+
46+
// wrap the MapView as an AndroidView
47+
AndroidView(
48+
modifier = modifier,
49+
factory = { mapView },
50+
// recomposes the MapView on changes in the MapViewState
51+
update = { mapView ->
52+
mapView.apply {
53+
map = mapViewState.arcGISMap
54+
setViewpoint(mapViewState.viewpoint)
55+
}
56+
}
57+
)
58+
59+
// launch coroutine functions in the composition's CoroutineContext
60+
LaunchedEffect(Unit) {
61+
mapView.onSingleTapConfirmed.collect {
62+
// call identifyLayers when a tap event occurs
63+
val identifyResult = mapView.identifyLayers(
64+
screenCoordinate = it.screenCoordinate,
65+
tolerance = 12.0,
66+
returnPopupsOnly = false,
67+
maximumResults = 10
68+
)
69+
mapViewModel.handleIdentifyResult(identifyResult)
70+
}
71+
}
72+
}
73+
74+
/**
75+
* Create the MapView instance and add it to the Activity lifecycle
76+
*/
77+
@Composable
78+
fun createMapViewInstance(lifecycleOwner: LifecycleOwner): MapView {
79+
// create the MapView
80+
val mapView = MapView(LocalContext.current)
81+
// add the side effects for MapView composition
82+
DisposableEffect(lifecycleOwner) {
83+
lifecycleOwner.lifecycle.addObserver(mapView)
84+
onDispose {
85+
lifecycleOwner.lifecycle.removeObserver(mapView)
86+
}
87+
}
88+
return mapView
89+
}

0 commit comments

Comments
 (0)