View on GitHub Sample viewer app

This sample demonstrates how to keep the viewpoints of two GeoViews (a 2D MapView and a 3D SceneView) synchronized with each other.

Screenshot of match viewpoint of geo views

Use case

You might need to synchronize GeoView viewpoints if you had two map views in one application - a main map and an inset. An inset map view could display all the layers at their full extent and contain a hollow rectangular graphic that represents the visible extent of the main map view. As you zoom or pan in the main map view, the extent graphic in the inset map would adjust accordingly.

How to use the sample

Interact with the MapView or SceneView by zooming or panning. The other MapView or SceneView will automatically focus on the same viewpoint.

How it works

  1. The ViewModel creates two containers: an ArcGISMap and an ArcGISScene. Both are initialized with the same initial Viewpoint (center coordinate and scale).
  2. The ViewModel also exposes a MapViewProxy and a SceneViewProxy. These proxies provide convenience functions to set viewpoints on the map/scene from the ViewModel without needing direct MapView/SceneView references.
  3. Each GeoView composable registers two callbacks:
    • onNavigationChanged: notifies when the user is actively navigating (panning/zooming/rotating).
    • onViewpointChangedForCenterAndScale: notifies about center-and-scale viewpoint updates.
  4. When the MapView viewpoint changes and the SceneView is not currently navigating, the ViewModel sets the SceneViewProxy to the new viewpoint. Symmetrically, when the SceneView viewpoint changes and the MapView is not navigating, the ViewModel sets the MapViewProxy to that viewpoint.

Relevant API

  • GeoView
  • MapView
  • SceneView
  • Viewpoint

About the data

This application provides two different perspectives of the arcGISImagery basemap, A 2D MapView as well as a 3D SceneView, displayed side by side.

Tags

3D, automatic refresh, event, event handler, events, extent, interaction, interactions, pan, zoom

Sample Code

MainActivity.kt MainActivity.kt MatchViewpointOfGeoViewsScreen.kt MatchViewpointOfGeoViewsViewModel.kt
/* Copyright 2026 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.arcgismaps.sample.matchviewpointofgeoviews
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import com.arcgismaps.ApiKey
import com.arcgismaps.ArcGISEnvironment
import com.esri.arcgismaps.sample.sampleslib.theme.SampleAppTheme
import com.esri.arcgismaps.sample.matchviewpointofgeoviews.screens.MatchViewpointOfGeoViewsScreen
class MainActivity : ComponentActivity() {
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
ArcGISEnvironment.apiKey = ApiKey.create(BuildConfig.ACCESS_TOKEN)
setContent {
SampleAppTheme {
MatchViewpointOfGeoViewsApp()
}
}
}
@Composable
private fun MatchViewpointOfGeoViewsApp() {
Surface(color = MaterialTheme.colorScheme.background) {
MatchViewpointOfGeoViewsScreen(
sampleName = getString(R.string.match_viewpoint_of_geo_views_app_name)
)
}
}
}