GroundImageState
GroundImageState manages the configuration and behavior of ground image overlays on the map. It provides reactive properties for geographic bounds, image resources, and opacity settings.
Constructor
Section titled “Constructor”GroundImageState( bounds: GeoRectBounds, image: Drawable, opacity: Float = 1.0f, id: String? = null, extra: Serializable? = null)Properties
Section titled “Properties”Core Properties
Section titled “Core Properties”id: String: Unique identifier (auto-generated if not provided)bounds: GeoRectBounds: Geographic rectangular bounds for image placementimage: Drawable: The drawable image to displayopacity: Float: Transparency level (0.0 = transparent, 1.0 = opaque)extra: Serializable?: Additional data attached to the ground image
Methods
Section titled “Methods”fun fingerPrint(): GroundImageFingerPrint // Change detectionfun asFlow(): Flow<GroundImageFingerPrint> // Reactive updatesUsage Examples
Section titled “Usage Examples”Basic Ground Image
Section titled “Basic Ground Image”@Composablefun BasicGroundImageExample() { val context = LocalContext.current val drawable = AppCompatResources.getDrawable(context, R.drawable.overlay_image)
val groundImageState = drawable?.let { GroundImageState( bounds = GeoRectBounds( southwest = GeoPointImpl.fromLatLong(37.7649, -122.4294), northeast = GeoPointImpl.fromLatLong(37.7849, -122.4094) ), image = it, opacity = 0.7f, extra = "Base overlay" ) }
// Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapViewMapView(state = mapViewState) { groundImageState?.let { state -> GroundImage(state) } }}Interactive Ground Image
Section titled “Interactive Ground Image”@Composablefun InteractiveGroundImageExample() { var groundImageState by remember { mutableStateOf<GroundImageState?>(null) } var opacity by remember { mutableStateOf(0.7f) }
val context = LocalContext.current
LaunchedEffect(opacity) { val drawable = AppCompatResources.getDrawable(context, R.drawable.map_overlay) drawable?.let { groundImageState = GroundImageState( bounds = GeoRectBounds( southwest = GeoPointImpl.fromLatLong(37.7649, -122.4294), northeast = GeoPointImpl.fromLatLong(37.7849, -122.4094) ), image = it, opacity = opacity, extra = "Interactive overlay" ) } }
Column { Slider( value = opacity, onValueChange = { opacity = it }, valueRange = 0f..1f, modifier = Modifier.padding(16.dp) ) Text("Opacity: ${(opacity * 100).toInt()}%")
// Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapViewMapView( state = mapViewState, onGroundImageClick = { event -> println("Ground image clicked at: ${event.clicked}") } ) { groundImageState?.let { state -> GroundImage(state) } } }}Multiple Overlays
Section titled “Multiple Overlays”@Composablefun MultiLayerGroundImageExample() { val context = LocalContext.current
val overlayStates = remember { listOf( Triple(R.drawable.base_layer, 0.3f, "Base satellite"), Triple(R.drawable.weather_layer, 0.6f, "Weather data"), Triple(R.drawable.traffic_layer, 0.8f, "Traffic info") ).mapNotNull { (resId, opacity, description) -> AppCompatResources.getDrawable(context, resId)?.let { drawable -> GroundImageState( bounds = GeoRectBounds( southwest = GeoPointImpl.fromLatLong(37.7649, -122.4294), northeast = GeoPointImpl.fromLatLong(37.7849, -122.4094) ), image = drawable, opacity = opacity, extra = description ) } } }
// Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapViewMapView(state = mapViewState) { overlayStates.forEach { state -> GroundImage(state) } }}Dynamic Bounds
Section titled “Dynamic Bounds”@Composablefun DynamicBoundsExample() { var southwest by remember { mutableStateOf(GeoPointImpl.fromLatLong(37.7649, -122.4294)) } var northeast by remember { mutableStateOf(GeoPointImpl.fromLatLong(37.7849, -122.4094)) }
val context = LocalContext.current val drawable = AppCompatResources.getDrawable(context, R.drawable.floor_plan)
val groundImageState = drawable?.let { GroundImageState( bounds = GeoRectBounds(southwest = southwest, northeast = northeast), image = it, opacity = 0.8f, extra = "Floor plan" ) }
// Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapViewMapView( state = mapViewState, onMarkerDrag = { markerState -> when (markerState.extra) { "SW" -> southwest = markerState.position "NE" -> northeast = markerState.position } } ) { groundImageState?.let { state -> GroundImage(state) }
// Corner markers Marker( position = southwest, icon = DefaultIcon(fillColor = Color.Green, label = "SW"), draggable = true, extra = "SW" )
Marker( position = northeast, icon = DefaultIcon(fillColor = Color.Red, label = "NE"), draggable = true, extra = "NE" ) }}Animated Overlay
Section titled “Animated Overlay”@Composablefun AnimatedGroundImageExample() { var isAnimating by remember { mutableStateOf(false) } var opacity by remember { mutableStateOf(0.5f) }
LaunchedEffect(isAnimating) { if (isAnimating) { while (isAnimating) { delay(100) opacity = (sin(System.currentTimeMillis() / 1000.0).toFloat() + 1f) / 2f } } }
val context = LocalContext.current val drawable = AppCompatResources.getDrawable(context, R.drawable.animated_overlay)
val groundImageState = drawable?.let { GroundImageState( bounds = GeoRectBounds( southwest = GeoPointImpl.fromLatLong(37.7649, -122.4294), northeast = GeoPointImpl.fromLatLong(37.7849, -122.4094) ), image = it, opacity = opacity, extra = "Animated overlay" ) }
Column { Button(onClick = { isAnimating = !isAnimating }) { Text(if (isAnimating) "Stop" else "Animate") }
// Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapViewMapView(state = mapViewState) { groundImageState?.let { state -> GroundImage(state) } } }}Event Handling
Section titled “Event Handling”Ground image events provide both the state and click location:
data class GroundImageEvent( val state: GroundImageState, val clicked: GeoPointImpl?)
typealias OnGroundImageEventHandler = (GroundImageEvent) -> UnitImage Resource Management
Section titled “Image Resource Management”Loading from Different Sources
Section titled “Loading from Different Sources”// From resourcesval drawable = AppCompatResources.getDrawable(context, R.drawable.overlay)
// From assetsval inputStream = context.assets.open("overlays/map.png")val drawable = Drawable.createFromStream(inputStream, null)
// From network (with image loading library)// Use libraries like Coil, Glide, or Picasso for network imagesBest Practices
Section titled “Best Practices”- Image Size: Optimize image resolution for performance
- Bounds Accuracy: Ensure precise geographic alignment
- Opacity: Use appropriate transparency for visibility
- Resource Management: Cache and reuse drawable resources
- Layer Order: Consider drawing order for multiple overlays
- Performance: Limit the number of simultaneous ground images
- Error Handling: Handle cases where images fail to load