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.
This hook runs before the component responds to input and can run again within
the same gesture. It does not report when camera movement ends.
For moving the camera from app code, see Control the camera.
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.
A null pointer-type, button, or modifier filter matches any value. Key mappings
default to exactly no modifiers; set modifiers = null to match a key with any
modifiers.
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.
Pass gestures from your own code
Section titled “Pass gestures from your own code”Code that recognizes gestures itself can pass them through MapState.panBy, MapState.scaleBy,
MapState.fling, and MapState.click. They follow the
camera permissions and callbacks in MapInteractions and report
CameraMoveReason.GESTURE, like a pointer gesture. They take logical
pixels and do nothing while no map is presented. See
Present on an Android Surface.
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) } } } })