Skip to content

Commit 237e046

Browse files
committed
feat: support dynamic anchor and zIndex in Clustering
1 parent b5f38e8 commit 237e046

3 files changed

Lines changed: 76 additions & 3 deletions

File tree

maps-app/src/main/java/com/google/maps/android/compose/markerexamples/MarkerClusteringActivity.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import com.google.maps.android.compose.GoogleMap
4949
import com.google.maps.android.compose.MapsComposeExperimentalApi
5050
import com.google.maps.android.compose.MarkerInfoWindow
5151
import com.google.maps.android.compose.clustering.Clustering
52+
import com.google.maps.android.compose.clustering.clusteringMarkerProperties
5253
import com.google.maps.android.compose.clustering.rememberClusterManager
5354
import com.google.maps.android.compose.clustering.rememberClusterRenderer
5455
import com.google.maps.android.compose.rememberCameraPositionState
@@ -161,6 +162,7 @@ private fun DefaultClustering(items: List<MyItem>) {
161162
@OptIn(MapsComposeExperimentalApi::class)
162163
@Composable
163164
private fun CustomUiClustering(items: List<MyItem>) {
165+
var selectedItem by remember { mutableStateOf<MyItem?>(null) }
164166
Clustering(
165167
items = items,
166168
// Optional: Handle clicks on clusters, cluster items, and cluster item info windows
@@ -170,6 +172,7 @@ private fun CustomUiClustering(items: List<MyItem>) {
170172
},
171173
onClusterItemClick = {
172174
Log.d(TAG, "Cluster item clicked! $it")
175+
selectedItem = if (selectedItem == it) null else it
173176
false
174177
},
175178
onClusterItemInfoWindowClick = {
@@ -184,7 +187,20 @@ private fun CustomUiClustering(items: List<MyItem>) {
184187
)
185188
},
186189
// Optional: Custom rendering for non-clustered items
187-
clusterItemContent = null,
190+
clusterItemContent = { item ->
191+
val isSelected = item == selectedItem
192+
if (isSelected) {
193+
clusteringMarkerProperties(
194+
anchor = Offset(0.5f, 0.5f),
195+
zIndex = 1.0f
196+
)
197+
}
198+
CircleContent(
199+
modifier = Modifier.size(if (isSelected) 40.dp else 20.dp),
200+
text = "",
201+
color = if (isSelected) Color.Red else Color.Green,
202+
)
203+
},
188204
clusterContentAnchor = Offset(0.5f, 0.5f),
189205
// Optional: Customization hook for clusterManager and renderer when they're ready
190206
onClusterManager = { clusterManager ->

maps-compose-utils/src/main/java/com/google/maps/android/compose/clustering/ClusterRenderer.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ internal class ComposeUiClusterRenderer<T : ClusterItem>(
144144
when (key) {
145145
is ViewKey.Cluster -> getMarker(key.cluster)
146146
is ViewKey.Item -> getMarker(key.item)
147-
}?.setIcon(renderViewToBitmapDescriptor(view))
147+
}?.apply {
148+
setIcon(renderViewToBitmapDescriptor(view))
149+
view.properties.anchor?.let { setAnchor(it.x, it.y) }
150+
view.properties.zIndex?.let { zIndex = it }
151+
}
148152
}
149153

150154
}
@@ -235,10 +239,20 @@ internal class ComposeUiClusterRenderer<T : ClusterItem>(
235239
private val content: @Composable () -> Unit,
236240
) : AbstractComposeView(context) {
237241

242+
val properties = ClusteringMarkerProperties()
238243
var onInvalidate: (() -> Unit)? = null
239244

240245
@Composable
241-
override fun Content() = content()
246+
override fun Content() {
247+
androidx.compose.runtime.LaunchedEffect(properties.anchor, properties.zIndex) {
248+
invalidate()
249+
}
250+
androidx.compose.runtime.CompositionLocalProvider(
251+
LocalClusteringMarkerProperties provides properties
252+
) {
253+
content()
254+
}
255+
}
242256

243257
override fun onDescendantInvalidated(child: View, target: View) {
244258
super.onDescendantInvalidated(child, target)

maps-compose-utils/src/main/java/com/google/maps/android/compose/clustering/Clustering.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import androidx.compose.runtime.mutableStateOf
1111
import androidx.compose.runtime.remember
1212
import androidx.compose.runtime.rememberUpdatedState
1313
import androidx.compose.runtime.snapshotFlow
14+
import androidx.compose.runtime.CompositionLocalProvider
15+
import androidx.compose.runtime.getValue
16+
import androidx.compose.runtime.mutableStateOf
17+
import androidx.compose.runtime.remember
18+
import androidx.compose.runtime.setValue
19+
import androidx.compose.runtime.staticCompositionLocalOf
1420
import androidx.compose.ui.UiComposable
1521
import androidx.compose.ui.geometry.Offset
1622
import androidx.compose.ui.platform.LocalContext
@@ -31,6 +37,43 @@ import com.google.maps.android.compose.rememberReattachClickListenersHandle
3137
import kotlinx.coroutines.awaitCancellation
3238
import kotlinx.coroutines.launch
3339

40+
/**
41+
* Properties for a marker in [Clustering].
42+
*/
43+
public class ClusteringMarkerProperties {
44+
public var anchor: Offset? by mutableStateOf(null)
45+
internal set
46+
public var zIndex: Float? by mutableStateOf(null)
47+
internal set
48+
}
49+
50+
/**
51+
* [CompositionLocal] used to provide [ClusteringMarkerProperties] to the content of a cluster or
52+
* cluster item.
53+
*/
54+
public val LocalClusteringMarkerProperties: androidx.compose.runtime.ProvidableCompositionLocal<ClusteringMarkerProperties> =
55+
staticCompositionLocalOf { ClusteringMarkerProperties() }
56+
57+
/**
58+
* Helper function to specify properties for the marker representing a cluster or cluster item.
59+
*
60+
* @param anchor the anchor for the marker image. If null, the default anchor specified in
61+
* [Clustering] will be used.
62+
* @param zIndex the z-index of the marker. If null, the default z-index specified in [Clustering]
63+
* will be used.
64+
*/
65+
@Composable
66+
public fun clusteringMarkerProperties(
67+
anchor: Offset? = null,
68+
zIndex: Float? = null,
69+
) {
70+
val properties = LocalClusteringMarkerProperties.current
71+
SideEffect {
72+
properties.anchor = anchor
73+
properties.zIndex = zIndex
74+
}
75+
}
76+
3477
/**
3578
* Groups many items on a map based on zoom level.
3679
*

0 commit comments

Comments
 (0)