Skip to content
This site is a preview of pull request #1363.

Overlay Compose UI

MaplibreMap draws controls on top of the map. The overlay block replaces the default controls when you supply it. The default draws a scale bar and a compass along the top edge. It draws the MapLibre logo and an attribution button along the bottom edge. The scale bar and the compass appear only while they are relevant.

App.kt
MaplibreMap()

Two variants cover common needs. MapOverlay.Full adds zoom in and zoom out buttons at the middle of the end edge. MapOverlay.AttributionOnly draws only the logo and the attribution button.

An empty block, or MapOverlay.None, draws no controls. Use it when your app shows the attribution somewhere else, such as an about screen.

App.kt
MaplibreMap {}

The trailing block draws the controls that you list. Modifier.align positions a control against an inset edge of the map.

App.kt
MaplibreMap {
MaplibreLogo(Modifier.align(Alignment.BottomStart))
ExpandingAttributionButton(
modifier = Modifier.align(Alignment.TopEnd),
contentAlignment = Alignment.TopEnd,
)
}

The base library draws controls with a fixed palette that stays legible on any basemap. The maplibre-compose-material3 module draws the same controls with your Material 3 color scheme and typography. Add the dependency:

libs.versions.toml
[libraries]
maplibre-composeMaterial3 = { module = "org.maplibre.compose:maplibre-compose-material3", version = "0.15.0" }
build.gradle.kts
commonMain.dependencies {
implementation(libs.maplibre.composeMaterial3)
}

MapOverlay.Material3 draws the same controls as MapOverlay.Default in the same places. Include it in the block:

App.kt
MaplibreMap { include(MapOverlay.Material3) }

MapOverlay.Material3AttributionOnly and MapOverlay.Material3Full apply the theme to the other presets.

Each Material 3 control is also a composable that you can place in the trailing block:

App.kt
MaplibreMap {
ScaleBar(
mapState.viewport?.metersPerDpAtTarget ?: 0.0,
modifier = Modifier.align(Alignment.TopStart),
) // (1)!
CompassButton(modifier = Modifier.align(Alignment.TopEnd))
ZoomButtons(Modifier.align(Alignment.CenterEnd))
MaplibreLogo(Modifier.align(Alignment.BottomStart))
ExpandingAttributionButton(
modifier = Modifier.align(Alignment.BottomEnd),
contentAlignment = Alignment.BottomEnd,
)
}
  1. ScaleBar and CompassButton stay on screen. The Disappearing versions that MapOverlay.Material3 uses fade in when the zoom or the orientation changes, and fade out once it settles.

Use contentWindowInsets to inset overlay controls. Use cameraPadding to shift the camera center. They can use the same values or vary independently.

App.kt
val mapInsets = WindowInsets.safeDrawing.union(WindowInsets(bottom = 128.dp))
MaplibreMap(
contentWindowInsets = mapInsets, // (1)!
cameraPadding = mapInsets.asPaddingValues(),
)
  1. union takes the larger inset on each edge.

Padding on a bounding-box camera move adds to cameraPadding for that fit.

MapOverlayScope.placedAt puts a child on a geographic position. Include MapOverlay.Default to keep the default controls. A pan, a zoom, or a window resize moves the child with the map.

App.kt
MaplibreMap {
include(MapOverlay.Default)
Text(
"Next sailing 12:40",
Modifier.placedAt(position, Alignment.BottomCenter).padding(bottom = 8.dp), // (1)!
)
}
  1. Alignment.BottomCenter sits the bottom edge of the chip on the point. Padding lifts the chip above the feature.

MapOverlayScope.placedTowards puts a child on the edge of an ellipse inscribed in the unobstructed map region, on the line towards a geographic position. The child appears only while the position projects outside of that ellipse. A position near a corner of the map region can be visible and still lie outside the ellipse.

App.kt
MaplibreMap {
include(MapOverlay.Default)
val placement = rememberPlacedTowardsState() // (1)!
Text(
"▲",
Modifier.placedTowards(position, placement).graphicsLayer {
rotationZ = placement.angleDegrees // (2)!
},
)
}
  1. The state stores the placement that the overlay computed.
  2. angleDegrees is the direction of the target, clockwise from screen-up.

PointerPinButton from the Material 3 module uses this modifier to display a pin-shaped button that points at the target.