Handle map input and clicks
Users can pan, zoom, rotate, and tilt the map by default. Two builders configure
input. MapInteractions sets which camera movements are allowed and
how your app responds to clicks. MapUiOptions sets what gestures,
scrolling, and keys do.
Restrict camera movement
Section titled “Restrict camera movement”For a map that users can pan and zoom but cannot rotate or tilt, disable those camera movements:
MaplibreMap( interactions = MapInteractions { camera { rotate { enabled = false } tilt { enabled = false } } })Omitted settings keep their defaults. Use MapInteractions(from = existing)
to build on another configuration. MapInteractions.None disallows every
camera movement. MapUiOptions.None disables every gesture, scroll, and key
binding, including feature clicks.
To stop following the user’s location when they
pan, use camera.pan.onStart.
For moving the camera from app code, see Control the camera.
Handle map clicks
Section titled “Handle map clicks”Use callbacks.click to act on a geographic location. For example, pass the
clicked position to your app:
@Composablefun ClickableMap(onLocationSelected: (Position) -> Unit) { MaplibreMap( interactions = MapInteractions { callbacks { click { onEvent { event -> event.position?.let(onLocationSelected) ClickResult.Consume } } } } )}Return ClickResult.Consume when your app handles the click, or
ClickResult.Pass to let it continue to interactive layers.
Use longClick for a long press or secondary mouse click.
Select layer features
Section titled “Select layer features”A layer’s onClick receives the features under the pointer. Use hitPadding
to make small features easier to select:
val state = rememberMapState { val interactiveAmtrakStations = rememberGeoJsonSource(GeoJsonData.Uri(Res.getUri("files/data/amtrak_stations.geojson"))) CircleLayer( id = "amtrak-stations", source = interactiveAmtrakStations, hitPadding = 12.dp, onClick = { features -> println("Clicked on ${features[0].toJson()}") ClickResult.Consume }, )}MaplibreMap(state = state)Layers receive clicks from front to back until a handler returns
ClickResult.Consume. Use callbacks.click.onUnhandled for clicks that no
layer handles, such as clearing an app’s selection.
Change scroll controls
Section titled “Change scroll controls”Vertical scrolling zooms by default. This example makes scrolling pan the map, while Ctrl-scroll zooms:
MaplibreMap( uiOptions = MapUiOptions { bindings { scroll { mappings { on(modifiers = Containing(KeyModifier.Ctrl), response = ScrollResponse.Zoom) otherwise(ScrollResponse.Pan) } } } })A mappings block replaces the default responses for that input. Rows are
tried from top to bottom; otherwise handles the remaining input. Available
gestures depend on the input device and platform. A mapping cannot enable a
camera movement that MapInteractions disallows.
Snap rotation to bearings
Section titled “Snap rotation to bearings”Use camera.rotate.snapping to snap to nearby bearings after rotation ends.
Choose specific bearings or evenly spaced targets, such as the four cardinal
directions:
MaplibreMap( interactions = MapInteractions { camera { rotate { snapping { targets = BearingTargets.evenlySpaced(count = 4) tolerance = 7.0 } } } })Feel bearing notches
Section titled “Feel bearing notches”Use camera.rotate.haptics to add feedback at chosen bearings while rotating.
Haptics work independently of snapping and support Android, iOS, and macOS.
Combine notches with different emphasis levels:
MaplibreMap( interactions = MapInteractions { camera { rotate { haptics { notch(BearingTargets.evenlySpaced(24), HapticEmphasis.Subtle) notch(BearingTargets.evenlySpaced(4), HapticEmphasis.Standard) notch(BearingTargets.at(0.0), HapticEmphasis.Emphasized) } } } })Pass gestures from your own code
Section titled “Pass gestures from your own code”For hosts with their own gesture recognizer, use MapState.panBy,
MapState.scaleBy, MapState.fling, and
MapState.click. See
Present on an Android Surface for an example.