Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
Expand Down Expand Up @@ -184,6 +185,7 @@ private fun CustomUiClustering(items: List<MyItem>) {
},
// Optional: Custom rendering for non-clustered items
clusterItemContent = null,
clusterContentAnchor = Offset(0.5f, 0.5f),
// Optional: Customization hook for clusterManager and renderer when they're ready
onClusterManager = { clusterManager ->
(clusterManager.renderer as DefaultClusterRenderer).minClusterSize = 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.ui.platform.AbstractComposeView
import androidx.core.graphics.applyCanvas
import androidx.core.view.doOnAttach
import androidx.core.view.doOnDetach
import androidx.compose.ui.geometry.Offset
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory
Expand Down Expand Up @@ -41,6 +42,10 @@ internal class ComposeUiClusterRenderer<T : ClusterItem>(
private val viewRendererState: State<ComposeUiViewRenderer>,
private val clusterContentState: State<@Composable ((Cluster<T>) -> Unit)?>,
private val clusterItemContentState: State<@Composable ((T) -> Unit)?>,
private val clusterContentAnchorState: State<Offset>,
private val clusterItemContentAnchorState: State<Offset>,
private val clusterContentZIndexState: State<Float>,
private val clusterItemContentZIndexState: State<Float>,
) : DefaultClusterRenderer<T>(
context,
map,
Expand Down Expand Up @@ -144,6 +149,16 @@ internal class ComposeUiClusterRenderer<T : ClusterItem>(

}

override fun onBeforeClusterRendered(cluster: Cluster<T>, markerOptions: MarkerOptions) {
super.onBeforeClusterRendered(cluster, markerOptions)

if (clusterContentState.value != null) {
val anchor = clusterContentAnchorState.value
markerOptions.anchor(anchor.x, anchor.y)
markerOptions.zIndex(clusterContentZIndexState.value)
}
}

override fun getDescriptorForCluster(cluster: Cluster<T>): BitmapDescriptor {
return if (clusterContentState.value != null) {
val viewInfo = keysToViews.entries
Expand All @@ -165,6 +180,10 @@ internal class ComposeUiClusterRenderer<T : ClusterItem>(
?.value
?: createAndAddView(ViewKey.Item(item))
markerOptions.icon(renderViewToBitmapDescriptor(viewInfo.view))

val anchor = clusterItemContentAnchorState.value
markerOptions.anchor(anchor.x, anchor.y)
markerOptions.zIndex(clusterItemContentZIndexState.value)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.UiComposable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.LocalContext
import com.google.android.gms.maps.GoogleMap
import com.google.maps.android.clustering.Cluster
Expand Down Expand Up @@ -42,6 +43,10 @@ import kotlinx.coroutines.launch
* window of a non-clustered item
* @param clusterContent an optional Composable that is rendered for each [Cluster].
* @param clusterItemContent an optional Composable that is rendered for each non-clustered item.
* @param clusterContentAnchor the anchor for the cluster image
* @param clusterItemContentAnchor the anchor for the non-clustered item image
* @param clusterContentZIndex the z-index of the cluster
* @param clusterItemContentZIndex the z-index of the non-clustered item
* @param clusterRenderer an optional ClusterRenderer that can be used to specify the algorithm used by the rendering.
*/
@Composable
Expand Down Expand Up @@ -85,10 +90,21 @@ public fun <T : ClusterItem> Clustering(
onClusterItemInfoWindowLongClick: (T) -> Unit = { },
clusterContent: @[UiComposable Composable] ((Cluster<T>) -> Unit)? = null,
clusterItemContent: @[UiComposable Composable] ((T) -> Unit)? = null,
clusterContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterItemContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterContentZIndex: Float = 0.0f,
clusterItemContentZIndex: Float = 0.0f,
clusterRenderer: ClusterRenderer<T>? = null,
) {
val clusterManager = rememberClusterManager(clusterContent, clusterItemContent, clusterRenderer)
?: return
val clusterManager = rememberClusterManager(
clusterContent,
clusterItemContent,
clusterContentAnchor,
clusterItemContentAnchor,
clusterContentZIndex,
clusterItemContentZIndex,
clusterRenderer
) ?: return

SideEffect {
clusterManager.setOnClusterClickListener(onClusterClick)
Expand All @@ -114,6 +130,10 @@ public fun <T : ClusterItem> Clustering(
* window of a non-clustered item
* @param clusterContent an optional Composable that is rendered for each [Cluster].
* @param clusterItemContent an optional Composable that is rendered for each non-clustered item.
* @param clusterContentAnchor the anchor for the cluster image
* @param clusterItemContentAnchor the anchor for the non-clustered item image
* @param clusterContentZIndex the z-index of the cluster
* @param clusterItemContentZIndex the z-index of the non-clustered item
*/
@Composable
@GoogleMapComposable
Expand All @@ -126,6 +146,10 @@ public fun <T : ClusterItem> Clustering(
onClusterItemInfoWindowLongClick: (T) -> Unit = { },
clusterContent: @[UiComposable Composable] ((Cluster<T>) -> Unit)? = null,
clusterItemContent: @[UiComposable Composable] ((T) -> Unit)? = null,
clusterContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterItemContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterContentZIndex: Float = 0.0f,
clusterItemContentZIndex: Float = 0.0f,
) {
Clustering(
items = items,
Expand All @@ -135,6 +159,10 @@ public fun <T : ClusterItem> Clustering(
onClusterItemInfoWindowLongClick = onClusterItemInfoWindowLongClick,
clusterContent = clusterContent,
clusterItemContent = clusterItemContent,
clusterContentAnchor = clusterContentAnchor,
clusterItemContentAnchor = clusterItemContentAnchor,
clusterContentZIndex = clusterContentZIndex,
clusterItemContentZIndex = clusterItemContentZIndex,
onClusterManager = null,
)
}
Expand All @@ -151,6 +179,10 @@ public fun <T : ClusterItem> Clustering(
* window of a non-clustered item
* @param clusterContent an optional Composable that is rendered for each [Cluster].
* @param clusterItemContent an optional Composable that is rendered for each non-clustered item.
* @param clusterContentAnchor the anchor for the cluster image
* @param clusterItemContentAnchor the anchor for the non-clustered item image
* @param clusterContentZIndex the z-index of the cluster
* @param clusterItemContentZIndex the z-index of the non-clustered item
* @param onClusterManager an optional lambda invoked with the clusterManager as a param when both
* the clusterManager and renderer are set up, allowing callers a customization hook.
*/
Expand All @@ -165,10 +197,22 @@ public fun <T : ClusterItem> Clustering(
onClusterItemInfoWindowLongClick: (T) -> Unit = { },
clusterContent: @[UiComposable Composable] ((Cluster<T>) -> Unit)? = null,
clusterItemContent: @[UiComposable Composable] ((T) -> Unit)? = null,
clusterContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterItemContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterContentZIndex: Float = 0.0f,
clusterItemContentZIndex: Float = 0.0f,
onClusterManager: ((ClusterManager<T>) -> Unit)? = null,
) {
val clusterManager = rememberClusterManager<T>()
val renderer = rememberClusterRenderer(clusterContent, clusterItemContent, clusterManager)
val renderer = rememberClusterRenderer(
clusterContent,
clusterItemContent,
clusterContentAnchor,
clusterItemContentAnchor,
clusterContentZIndex,
clusterItemContentZIndex,
clusterManager
)

SideEffect {
clusterManager ?: return@SideEffect
Expand Down Expand Up @@ -266,17 +310,29 @@ public fun <T : ClusterItem> rememberClusterRenderer(
*
* @param clusterContent an optional Composable that is rendered for each [Cluster].
* @param clusterItemContent an optional Composable that is rendered for each non-clustered item.
* @param clusterContentAnchor the anchor for the cluster image
* @param clusterItemContentAnchor the anchor for the non-clustered item image
* @param clusterContentZIndex the z-index of the cluster
* @param clusterItemContentZIndex the z-index of the non-clustered item
*/
@Composable
@GoogleMapComposable
@MapsComposeExperimentalApi
public fun <T : ClusterItem> rememberClusterRenderer(
clusterContent: @Composable ((Cluster<T>) -> Unit)?,
clusterItemContent: @Composable ((T) -> Unit)?,
clusterContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterItemContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterContentZIndex: Float = 0.0f,
clusterItemContentZIndex: Float = 0.0f,
clusterManager: ClusterManager<T>?,
): ClusterRenderer<T>? {
val clusterContentState = rememberUpdatedState(clusterContent)
val clusterItemContentState = rememberUpdatedState(clusterItemContent)
val clusterContentAnchorState = rememberUpdatedState(clusterContentAnchor)
val clusterItemContentAnchorState = rememberUpdatedState(clusterItemContentAnchor)
val clusterContentZIndexState = rememberUpdatedState(clusterContentZIndex)
val clusterItemContentZIndexState = rememberUpdatedState(clusterItemContentZIndex)
val context = LocalContext.current
val viewRendererState = rememberUpdatedState(rememberComposeUiViewRenderer())
val clusterRendererState: MutableState<ClusterRenderer<T>?> = remember { mutableStateOf(null) }
Expand All @@ -291,6 +347,10 @@ public fun <T : ClusterItem> rememberClusterRenderer(
viewRendererState,
clusterContentState,
clusterItemContentState,
clusterContentAnchorState,
clusterItemContentAnchorState,
clusterContentZIndexState,
clusterItemContentZIndexState,
)
clusterRendererState.value = renderer
awaitCancellation()
Expand All @@ -315,10 +375,18 @@ public fun <T : ClusterItem> rememberClusterManager(): ClusterManager<T>? {
private fun <T : ClusterItem> rememberClusterManager(
clusterContent: @Composable ((Cluster<T>) -> Unit)?,
clusterItemContent: @Composable ((T) -> Unit)?,
clusterContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterItemContentAnchor: Offset = Offset(0.5f, 1.0f),
clusterContentZIndex: Float = 0.0f,
clusterItemContentZIndex: Float = 0.0f,
clusterRenderer: ClusterRenderer<T>? = null,
): ClusterManager<T>? {
val clusterContentState = rememberUpdatedState(clusterContent)
val clusterItemContentState = rememberUpdatedState(clusterItemContent)
val clusterContentAnchorState = rememberUpdatedState(clusterContentAnchor)
val clusterItemContentAnchorState = rememberUpdatedState(clusterItemContentAnchor)
val clusterContentZIndexState = rememberUpdatedState(clusterContentZIndex)
val clusterItemContentZIndexState = rememberUpdatedState(clusterItemContentZIndex)
val context = LocalContext.current
val viewRendererState = rememberUpdatedState(rememberComposeUiViewRenderer())
val clusterManagerState: MutableState<ClusterManager<T>?> = remember { mutableStateOf(null) }
Expand All @@ -332,14 +400,18 @@ private fun <T : ClusterItem> rememberClusterManager(
.collect { hasCustomContent ->
val renderer = clusterRenderer
?: if (hasCustomContent) {
ComposeUiClusterRenderer(
ComposeUiClusterRenderer<T>(
context,
scope = this,
map,
clusterManager,
viewRendererState,
clusterContentState,
clusterItemContentState,
clusterContentAnchorState,
clusterItemContentAnchorState,
clusterContentZIndexState,
clusterItemContentZIndexState,
)
} else {
DefaultClusterRenderer(context, map, clusterManager)
Expand Down