Add Navigation Controls
This tutorial shows how to add zoom buttons, compass, and location buttons as on-screen controls for your MapMetrics Android map.
Prerequisites
- Completed the Getting Started Guide
- A MapMetrics API key and style URL from the MapMetrics Portal
Built-in Compass Control
The compass appears automatically when the map is rotated and resets bearing to north on tap:
kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.maplibre.android.camera.CameraPosition
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.maps.MapView
import org.maplibre.android.maps.MapMetricsMap
import org.maplibre.android.maps.Style
class NavigationControlsActivity : AppCompatActivity() {
private lateinit var mapView: MapView
private lateinit var map: MapMetricsMap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map)
mapView = findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapMetricsMap ->
map = mapMetricsMap
val ui = map.uiSettings
// Compass — shows when map is rotated, taps resets to north
ui.isCompassEnabled = true
ui.setCompassFadeFacingNorth(true) // hide when facing north
map.setStyle(
Style.Builder().fromUri(
"https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY"
)
)
map.cameraPosition = CameraPosition.Builder()
.target(LatLng(48.8566, 2.3522))
.zoom(12.0)
.build()
}
}
override fun onStart() { super.onStart(); mapView.onStart() }
override fun onResume() { super.onResume(); mapView.onResume() }
override fun onPause() { super.onPause(); mapView.onPause() }
override fun onStop() { super.onStop(); mapView.onStop() }
override fun onDestroy() { super.onDestroy(); mapView.onDestroy() }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}Custom Zoom Buttons
Add plus/minus zoom buttons as a floating overlay:
kotlin
import android.widget.ImageButton
import org.maplibre.android.camera.CameraUpdateFactory
private fun setupZoomControls() {
findViewById<ImageButton>(R.id.btnZoomIn).setOnClickListener {
map.animateCamera(CameraUpdateFactory.zoomIn(), 300)
}
findViewById<ImageButton>(R.id.btnZoomOut).setOnClickListener {
map.animateCamera(CameraUpdateFactory.zoomOut(), 300)
}
}Layout overlay for zoom buttons:
xml
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="16dp"
android:orientation="vertical">
<ImageButton
android:id="@+id/btnZoomIn"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_add"
android:background="@drawable/btn_round_bg"
android:contentDescription="Zoom in" />
<ImageButton
android:id="@+id/btnZoomOut"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="8dp"
android:src="@drawable/ic_remove"
android:background="@drawable/btn_round_bg"
android:contentDescription="Zoom out" />
</LinearLayout>My Location Button
Add a button to fly to the user's GPS location:
kotlin
import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import org.maplibre.android.location.LocationComponentActivationOptions
import org.maplibre.android.location.modes.CameraMode
private fun setupLocationButton(style: Style) {
findViewById<ImageButton>(R.id.btnMyLocation).setOnClickListener {
if (ActivityCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
enableLocationAndFly(style)
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
LOCATION_REQUEST_CODE
)
}
}
}
private fun enableLocationAndFly(style: Style) {
val locationComponent = map.locationComponent
locationComponent.activateLocationComponent(
LocationComponentActivationOptions.builder(this, style)
.useDefaultLocationEngine(true)
.build()
)
locationComponent.isLocationComponentEnabled = true
locationComponent.cameraMode = CameraMode.TRACKING
// Fly to current location
locationComponent.lastKnownLocation?.let { location ->
map.animateCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(location.latitude, location.longitude),
15.0
),
1500
)
}
}
companion object {
private const val LOCATION_REQUEST_CODE = 1001
}Reset North Button
Reset bearing and tilt to default:
kotlin
private fun setupResetNorthButton() {
findViewById<ImageButton>(R.id.btnNorth).setOnClickListener {
map.animateCamera(
CameraUpdateFactory.newCameraPosition(
CameraPosition.Builder(map.cameraPosition)
.bearing(0.0)
.tilt(0.0)
.build()
),
500
)
}
}Complete Control Panel
Combine all controls in one overlay:
xml
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="12dp"
android:orientation="vertical"
android:background="@drawable/controls_bg"
android:padding="4dp">
<ImageButton
android:id="@+id/btnZoomIn"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_add"
android:background="?selectableItemBackground"
android:contentDescription="Zoom in" />
<ImageButton
android:id="@+id/btnZoomOut"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_remove"
android:background="?selectableItemBackground"
android:contentDescription="Zoom out" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#DDDDDD"
android:layout_marginVertical="4dp" />
<ImageButton
android:id="@+id/btnNorth"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_compass"
android:background="?selectableItemBackground"
android:contentDescription="Reset north" />
<ImageButton
android:id="@+id/btnMyLocation"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_my_location"
android:background="?selectableItemBackground"
android:contentDescription="My location" />
</LinearLayout>Compass Settings
| Setting | XML Attribute | Description |
|---|---|---|
isCompassEnabled | maplibre_uiCompass | Show/hide compass |
setCompassFadeFacingNorth | maplibre_uiCompassFadeFacingNorth | Auto-hide when north up |
compassGravity | maplibre_uiCompassGravity | Screen position |
Next Steps
- Zoom Methods — Zoom API reference
- Location Component — User location tracking
- Set Pitch & Bearing — 3D camera controls
Tip: On mobile, keep navigation controls small (40-48dp) and place them on the right edge so they don't overlap the map's built-in compass (top-left by default) or attribution (bottom-left).