Add a scale bar to visually gauge distances on a map.
Use case
Allows a user to have a visual reference for distances when navigating the map.
How to use the sample
Zoom in or out of the map. The scale bar will automatically display the appropriate scale based on zoom level. Units can be in metric and/or imperial based on locale/optional settings.
How it works
- Create an
ArcGISMap
and add it to aMapView
composable. - Listen and track callback changes from
onUnitsPerDipChanged
,onViewpointChangedForCenterAndScale
,onSpatialReferenceChanged
using the composableMapView
. - Add the
Scalebar
composable positioned on top of theMapView
- Pass in the latest values of
unitsPerDip
,viewpoint
,spatialReference
and use a preferredmaxWidth
into theScaleBar
.
Relevant API
- ArcGISMap
- MapView
- Scalebar
- UnitSystem
Additional information
The scale will be accurate for the center of the map, and in general more accurate at larger scales (zoomed in). This means at smaller scales (zoomed out), the reading may be inaccurate at the extremes of the visible extent.
This sample uses the scale bar toolkit component, which requires the toolkit. For information about setting up the toolkit, as well as code for the underlying component, visit the the developer's documentation page.
Tags
map, measure, scale, toolkit
Sample Code
/* Copyright 2025 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.showscalebar.components
import android.app.Application
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableDoubleStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.arcgismaps.geometry.SpatialReference
import com.arcgismaps.mapping.ArcGISMap
import com.arcgismaps.mapping.BasemapStyle
import com.arcgismaps.mapping.Viewpoint
import com.esri.arcgismaps.sample.sampleslib.components.MessageDialogViewModel
import kotlinx.coroutines.launch
import kotlin.time.Duration
class ShowScaleBarViewModel(application: Application) : AndroidViewModel(application) {
// Create a message dialog view model for handling error messages
val messageDialogVM = MessageDialogViewModel()
val arcGISMap = ArcGISMap(BasemapStyle.ArcGISStreets).apply {
initialViewpoint = Viewpoint(33.723271, -117.945793, 30452.0)
}
// Scale bar properties updated by the composable mapview.
var viewpoint by mutableStateOf<Viewpoint?>(null)
private set
var unitsPerDip by mutableDoubleStateOf(Double.NaN)
private set
var spatialReference by mutableStateOf<SpatialReference?>(null)
private set
init {
viewModelScope.launch {
arcGISMap.load().onFailure { error ->
messageDialogVM.showMessageDialog(
title = "Failed to load map",
description = error.message.toString()
)
}
}
}
fun updateViewpoint(newViewpoint: Viewpoint?) {
viewpoint = newViewpoint
}
fun updateUnitsPerDip(newUnitsPerDip: Double) {
unitsPerDip = newUnitsPerDip
}
fun updateSpacialReference(newSpacialReference: SpatialReference?) {
spatialReference = newSpacialReference
}
}
/**
* Convert a duration to a string representation of seconds.
*/
fun Duration.durationToSeconds(): String {
return if (this == Duration.INFINITE) "Infinite" else this.inWholeSeconds.toString()
}