Show popup

View on GitHubSample viewer app

Show a predefined popup from a web map.

Show popup screenshot

Use case

Many web maps contain predefined popups which are used to display the attributes associated with each feature layer in the map, such as hiking trails, land values, or unemployment rates. You can display text, attachments, images, charts, and web links. Rather than creating new popups to display information, you can easily access and display the predefined popups.

How to use the sample

Tap on the features to prompt a popup that displays information about the feature.

How it works

  1. Create and load an ArcGISMap using a URL.
  2. Set the map to a MapView and add an onTouchListener.
  3. Use the MapView.identifyLayerAsync() method to identify the top-most feature.
  4. Attach the Popup from identifyLayerResultsFuture.get() to the PopupViewModel
  5. Present the view controller.

Relevant API

  • IdentifyLayerResult
  • ArcGISMap
  • PopupViewModel

About the data

This sample uses a feature layer that displays reported incidents in San Francisco.

Tags

feature, feature layer, popup, web map

Sample Code

MainActivity.ktMainActivity.ktPopupFragment.kt
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* Copyright 2021 Esri
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.esri.arcgisruntime.sample.showpopup

import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.esri.arcgisruntime.ArcGISRuntimeEnvironment
import com.esri.arcgisruntime.data.Feature
import com.esri.arcgisruntime.geometry.GeometryType
import com.esri.arcgisruntime.layers.FeatureLayer
import com.esri.arcgisruntime.mapping.ArcGISMap
import com.esri.arcgisruntime.mapping.view.DefaultMapViewOnTouchListener
import com.esri.arcgisruntime.mapping.view.MapView
import com.esri.arcgisruntime.portal.Portal
import com.esri.arcgisruntime.portal.PortalItem
import com.esri.arcgisruntime.sample.showpopup.databinding.ActivityMainBinding
import com.esri.arcgisruntime.toolkit.popup.PopupViewModel
import com.esri.arcgisruntime.toolkit.util.observeEvent
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlin.math.roundToInt

class MainActivity : AppCompatActivity() {

    private val TAG: String = MainActivity::class.java.simpleName

    private lateinit var bottomSheetBehavior: BottomSheetBehavior<View>
    private lateinit var mapView: MapView
    private lateinit var progressBar: ProgressBar
    private lateinit var map: ArcGISMap
    private val popupViewModel: PopupViewModel by viewModels()

    /**
     * getter function to retrieve the first available feature layer
     * [featureLayer] updates with every map click
     */
    private val featureLayer: FeatureLayer?
        get() {
            return map.operationalLayers?.filterIsInstance<FeatureLayer>()?.first {
                (it.featureTable?.geometryType == GeometryType.POINT)
                    .and(it.isVisible)
                    .and(it.isPopupEnabled && it.popupDefinition != null)
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // authentication with an API key or named user is required to access basemaps and other
        // location services
        ArcGISRuntimeEnvironment.setApiKey(BuildConfig.API_KEY)

        val binding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)

        binding.lifecycleOwner = this

        val portal = Portal("https://arcgisruntime.maps.arcgis.com/")
        val portalItem = PortalItem(portal, "fb788308ea2e4d8682b9c05ef641f273")
        map = ArcGISMap(portalItem)

        // set up binding and UI behaviour
        mapView = binding.mapView
        mapView.map = map
        progressBar = binding.progressBar
        bottomSheetBehavior = BottomSheetBehavior.from(binding.bottomSheetContainer)
        bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN

        // reset the IdentifyResult on a sheet close
        bottomSheetBehavior.addBottomSheetCallback(object :
            BottomSheetBehavior.BottomSheetCallback() {
            override fun onStateChanged(bottomSheet: View, newState: Int) {
                if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                    // Clear the selected features from the feature layer
                    resetIdentifyResult()
                }
            }

            override fun onSlide(bottomSheet: View, slideOffset: Float) {
            }
        })

        popupViewModel.dismissPopupEvent.observeEvent(this) {
            bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
            // Clear the selected features from the feature layer
            resetIdentifyResult()
        }

        // set the progressBar visibility
        progressBar.visibility = View.GONE

        mapView.onTouchListener =
            object : DefaultMapViewOnTouchListener(this, mapView) {
                override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
                    // set the progressBar visibility
                    progressBar.visibility = View.VISIBLE
                    bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
                    val screenPoint = android.graphics.Point(
                        event.x.roundToInt(),
                        event.y.roundToInt()
                    )
                    // setup identifiable layer at the given screen point.
                    identifyLayer(screenPoint)
                    return true
                }
            }
    }

    /**
     * Performs an identify on the feature layer at the given screen point.
     * [screenPoint] in Android graphic coordinates.
     */
    private fun identifyLayer(screenPoint: android.graphics.Point) {

        featureLayer?.let {
            // clear the selected features from the feature layer
            resetIdentifyResult()

            val identifyLayerResultsFuture = mapView
                .identifyLayerAsync(featureLayer, screenPoint, 12.0, true)

            identifyLayerResultsFuture.addDoneListener {
                try {
                    val identifyLayerResult = identifyLayerResultsFuture.get()

                    if (identifyLayerResult.popups.isNotEmpty()) {
                        popupViewModel.setPopup(identifyLayerResult.popups.first())
                        val featureLayer: FeatureLayer? =
                            identifyLayerResult.layerContent as? FeatureLayer
                        featureLayer?.selectFeature(identifyLayerResult.popups.first().geoElement as Feature)
                        bottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
                    }
                } catch (e: Exception) {
                    val error = "Error identifying results ${e.message}"
                    Log.e(TAG, error)
                    Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
                }

                // set the progressBar visibility
                progressBar.visibility = View.GONE
            }
        }
    }

    /**
     * Resets the Identify Result.
     */
    private fun resetIdentifyResult() {
        featureLayer?.clearSelection()
        popupViewModel.clearPopup()
    }

    override fun onPause() {
        mapView.pause()
        super.onPause()
    }

    override fun onResume() {
        super.onResume()
        mapView.resume()
    }

    override fun onDestroy() {
        mapView.dispose()
        super.onDestroy()
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.