From 6dfe858f43c14b20ce66e8c8dbaf557195c6caf5 Mon Sep 17 00:00:00 2001 From: Morgan Date: Tue, 29 Oct 2024 17:21:02 +0100 Subject: [PATCH] feat: customize MarkerInfoWindow's Marker using Composable (#384) --- .../android/compose/GoogleMapViewTests.kt | 23 ++++++ .../maps/android/compose/BasicMapActivity.kt | 24 ++++++ .../com/google/maps/android/compose/Marker.kt | 75 +++++++++++++++++++ 3 files changed, 122 insertions(+) diff --git a/app/src/androidTest/java/com/google/maps/android/compose/GoogleMapViewTests.kt b/app/src/androidTest/java/com/google/maps/android/compose/GoogleMapViewTests.kt index afbbab6f..d84eae28 100644 --- a/app/src/androidTest/java/com/google/maps/android/compose/GoogleMapViewTests.kt +++ b/app/src/androidTest/java/com/google/maps/android/compose/GoogleMapViewTests.kt @@ -250,6 +250,29 @@ class GoogleMapViewTests { } } + @Test(expected = IllegalStateException::class) + fun testMarkerStateInsideMarkerInfoWindowComposableCannotBeReused() { + initMap { + val markerState = rememberMarkerState() + MarkerInfoWindowComposable( + keys = arrayOf("marker1"), + state = markerState, + ) { + Box { + Text(text = "marker1") + } + } + MarkerInfoWindowComposable( + keys = arrayOf("marker2"), + state = markerState, + ) { + Box { + Text(text = "marker2") + } + } + } + } + @Test fun testCameraPositionStateMapClears() { initMap() diff --git a/app/src/main/java/com/google/maps/android/compose/BasicMapActivity.kt b/app/src/main/java/com/google/maps/android/compose/BasicMapActivity.kt index aaf3e47d..03be3a67 100644 --- a/app/src/main/java/com/google/maps/android/compose/BasicMapActivity.kt +++ b/app/src/main/java/com/google/maps/android/compose/BasicMapActivity.kt @@ -146,6 +146,7 @@ fun GoogleMapView( val singapore2State = rememberMarkerState(position = singapore2) val singapore3State = rememberMarkerState(position = singapore3) val singapore4State = rememberMarkerState(position = singapore4) + val singapore5State = rememberMarkerState(position = singapore5) var circleCenter by remember { mutableStateOf(singapore) } if (!singaporeState.isDragging) { @@ -229,6 +230,29 @@ fun GoogleMapView( ) } } + MarkerInfoWindowComposable( + keys = arrayOf("singapore5"), + state = singapore5State, + onClick = markerClick, + title = "Marker with custom Composable info window", + infoContent = { + Text(it.title ?: "Title", color = Color.Blue) + } + ) { + Box( + modifier = Modifier + .width(88.dp) + .height(36.dp) + .clip(RoundedCornerShape(16.dp)) + .background(Color.Red), + contentAlignment = Alignment.Center, + ) { + Text( + text = "Compose MarkerInfoWindow", + textAlign = TextAlign.Center, + ) + } + } Circle( center = circleCenter, diff --git a/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt b/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt index 762f460b..476701f6 100644 --- a/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt +++ b/maps-compose/src/main/java/com/google/maps/android/compose/Marker.kt @@ -404,6 +404,81 @@ public fun MarkerInfoWindow( ) } +/** + * A composable for a marker on the map wherein its entire info window and the marker itself can be + * customized. If this customization is not required, use + * [com.google.maps.android.compose.Marker]. + * + * @param keys unique keys representing the state of this Marker. Any changes to one of the key will + * trigger a rendering of the content composable and thus the rendering of an updated marker. + * @param state the [MarkerState] to be used to control or observe the marker + * state such as its position and info window + * @param alpha the alpha (opacity) of the marker + * @param anchor the anchor for the marker image + * @param draggable sets the draggability for the marker + * @param flat sets if the marker should be flat against the map + * @param infoWindowAnchor the anchor point of the info window on the marker image + * @param rotation the rotation of the marker in degrees clockwise about the marker's anchor point + * @param snippet the snippet for the marker + * @param tag optional tag to associate with the marker + * @param title the title for the marker + * @param visible the visibility of the marker + * @param zIndex the z-index of the marker + * @param onClick a lambda invoked when the marker is clicked + * @param onInfoWindowClick a lambda invoked when the marker's info window is clicked + * @param onInfoWindowClose a lambda invoked when the marker's info window is closed + * @param onInfoWindowLongClick a lambda invoked when the marker's info window is long clicked + * @param infoContent optional composable lambda expression for customizing the + * info window's content + * @param content composable lambda expression used to customize the marker's content + */ +@Composable +@GoogleMapComposable +public fun MarkerInfoWindowComposable( + vararg keys: Any, + state: MarkerState = rememberMarkerState(), + alpha: Float = 1.0f, + anchor: Offset = Offset(0.5f, 1.0f), + draggable: Boolean = false, + flat: Boolean = false, + infoWindowAnchor: Offset = Offset(0.5f, 0.0f), + rotation: Float = 0.0f, + snippet: String? = null, + tag: Any? = null, + title: String? = null, + visible: Boolean = true, + zIndex: Float = 0.0f, + onClick: (Marker) -> Boolean = { false }, + onInfoWindowClick: (Marker) -> Unit = {}, + onInfoWindowClose: (Marker) -> Unit = {}, + onInfoWindowLongClick: (Marker) -> Unit = {}, + infoContent: (@Composable (Marker) -> Unit)? = null, + content: @Composable () -> Unit, +) { + val icon = rememberComposeBitmapDescriptor(*keys) { content() } + + MarkerImpl( + state = state, + alpha = alpha, + anchor = anchor, + draggable = draggable, + flat = flat, + icon = icon, + infoWindowAnchor = infoWindowAnchor, + rotation = rotation, + snippet = snippet, + tag = tag, + title = title, + visible = visible, + zIndex = zIndex, + onClick = onClick, + onInfoWindowClick = onInfoWindowClick, + onInfoWindowClose = onInfoWindowClose, + onInfoWindowLongClick = onInfoWindowLongClick, + infoWindow = infoContent, + ) +} + /** * A composable for a marker on the map wherein its info window contents can be * customized. If this customization is not required, use