This example demonstrates the marker system in OpenMapView, including marker rendering, touch detection, info windows, and marker navigation.
- Multiple markers at real Bochum landmark locations
- Default teardrop marker icons with color variations
- Marker click detection and selection tracking
- Info windows showing marker titles and snippets with auto-dismiss
- Navigation between markers with prev/next buttons
- Info window toggle via FAB or marker tap
- Real-time status display (selection index, camera state)
- Visual feedback when info window is shown (red text)
- Open the OpenMapView project in Android Studio
- Select
examples.Example03Markersfrom the run configuration dropdown - Click Run (green play button)
- Deploy to your device or emulator
# From project root - build, install, and launch
./gradlew :examples:Example03Markers:installDebug
# Launch the app
adb shell am start -n de.afarber.openmapview.example03markers/.MainActivityexample03markers/
├── MainActivity.kt # Main activity and MapViewScreen composable
├── MarkerToolbar.kt # Horizontal toolbar with prev/next navigation buttons
├── StatusToolbar.kt # Status overlay showing selection index and camera state
├── MarkerData.kt # Marker data class and Bochum POI locations
└── Colors.kt # OSM-inspired colors and shared dimensions
@Composable
fun MapViewScreen() {
val lifecycleOwner = LocalLifecycleOwner.current
var mapView: OpenMapView? by remember { mutableStateOf(null) }
var selectedIndex by remember { mutableIntStateOf(0) }
var selectedMarker: Marker? by remember { mutableStateOf(null) }
var isInfoWindowShown by remember { mutableStateOf(false) }
Box(modifier = Modifier.fillMaxSize()) {
AndroidView(
factory = { ctx ->
OpenMapView(ctx).apply {
lifecycleOwner.lifecycle.addObserver(this)
setCenter(initialLocation)
setZoom(15.0f)
getUiSettings().infoWindowAutoDismiss = 5.seconds
setOnMarkerClickListener { marker ->
selectedMarker = marker
isInfoWindowShown = marker.isInfoWindowShown
true
}
setOnInfoWindowCloseListener {
isInfoWindowShown = false
}
mapView = this
}
},
modifier = Modifier.fillMaxSize(),
)
StatusToolbar(selectedIndex, selectedMarker?.title, cameraState, isInfoWindowShown, ...)
MarkerToolbar(onPrevClick = { ... }, onNextClick = { ... })
}
}addMarker(
Marker(
position = LatLng(51.4783, 7.2231),
title = "Bochum Hauptbahnhof",
snippet = "Main Railway Station",
icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED),
)
)addMarker(
MarkerOptions()
.position(LatLng(51.4650, 7.2500))
.title("Builder Pattern")
.snippet("Created with MarkerOptions")
.alpha(0.8f)
)- Marker: Data class with position, title, snippet, icon, anchor, and tag
- addMarker(): Add a marker to the map
- getMarkers(): Get list of all markers
- setOnMarkerClickListener(): Handle marker click events
- setOnInfoWindowClickListener(): Handle info window click events
- setOnInfoWindowCloseListener(): Handle info window close events (manual or auto-dismiss)
- Launch the app - you should see 6 colored markers at Bochum landmarks
- Tap a marker - info window shows title and snippet, status text turns red
- Tap the same marker again - info window closes, status text turns black
- Tap info window - toast message confirms the click
- Tap prev/next buttons - navigate between markers with camera animation
- Tap the FAB - toggles info window on selected marker
- Wait 10 seconds - info window auto-dismisses, status text turns black
- Pan/zoom the map - markers stay at correct geographic positions
To use custom marker icons instead of the default teardrop:
// Create custom bitmap (e.g., from resources)
val customIcon = BitmapFactory.decodeResource(
resources,
R.drawable.my_custom_marker
)
// Add marker with custom icon
addMarker(
Marker(
position = LatLng(51.4661, 7.2491),
title = "Custom Marker",
icon = customIcon,
anchor = Pair(0.5f, 1.0f) // Center-bottom anchor
)
)The anchor determines which point of the icon aligns with the geographic position:
Pair(0.5f, 1.0f)- Center horizontally, bottom vertically (default for pins)Pair(0.5f, 0.5f)- Center of iconPair(0.0f, 0.0f)- Top-left corner
Markers are drawn:
- On top of map tiles (layered correctly)
- In the order they were added (first added = bottom layer)
- With proper screen-to-geographic coordinate conversion
- Using the Web Mercator projection
Click detection uses:
- Bounding box hit testing on marker icons
- Reverse z-order checking (top markers checked first)
- Configurable movement threshold (10px) to distinguish clicks from drags
Default Center: Calculated from marker positions (~51.47°N, 7.22°E) at zoom 13.0
All 8 markers are positioned around Bochum at real landmark locations.
