You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose Google Maps多类型Marker按类别自定义聚类问题

按类别聚类实现方案

你可以根据业务场景选择以下两种可行实现:


方案1:修正多ClusterManager实现(改动量最小)

你之前的多ClusterManager写法缺失了事件分发逻辑,也没有处理页面重组时的重复渲染问题,修正后代码如下:

fun MapViewContainer(
    mapView: MapView,
    points: List<PointOfInterest>
) {
    val localContext = LocalContext.current
    val coroutineScope = rememberCoroutineScope()

    AndroidView({ mapView }) { map ->
        coroutineScope.launch {
            val googleMap = map.awaitMap().apply {
                // 先清空旧内容与监听,避免Compose重组导致重复渲染
                clear()
                setOnCameraIdleListener(null)
                setOnMarkerClickListener(null)
            }

            // 按类别自动分组POI,无需硬编码每个类别
            val groupedPoi = points.groupBy { it.category }
            val clusterManagers = mutableListOf<ClusterManager<PoiItem>>()

            groupedPoi.forEach { (_, poiList) ->
                val categoryClusterManager = ClusterManager<PoiItem>(localContext, googleMap)
                categoryClusterManager.renderer = PoiClusterRenderer(localContext, googleMap, categoryClusterManager)
                categoryClusterManager.addItems(poiList)
                clusterManagers.add(categoryClusterManager)
            }

            // 统一分发相机空闲事件触发所有类别的聚类
            googleMap.setOnCameraIdleListener {
                clusterManagers.forEach { it.cluster() }
            }

            // 统一分发Marker点击事件
            googleMap.setOnMarkerClickListener { marker ->
                clusterManagers.any { it.onMarkerClick(marker) }
            }
        }
    }
}

该方案优势:无需修改现有PoiItem、PoiClusterRenderer逻辑,不同类别的聚类完全独立,可单独控制某一类别的显隐。


方案2:自定义聚类算法(单ClusterManager实现)

如果不想维护多个ClusterManager实例,可以通过重写聚类判定逻辑实现,仅同类别的POI会被聚为同一簇:

步骤1:修改PoiItem暴露类别属性

class PoiItem(
    lat: Double,
    lng: Double,
    private val title: String,
    val category: Category, // 修改为公开可访问
    private val snippet: String
) : ClusterItem {
    private val position: LatLng = LatLng(lat, lng)
    override fun getPosition(): LatLng = position
    override fun getTitle(): String = title
    override fun getSnippet(): String = snippet
}

步骤2:自定义按类别聚类的算法

class CategoryClusterAlgorithm<T : PoiItem> : NonHierarchicalDistanceBasedAlgorithm<T>() {
    override fun getClusters(zoom: Double): MutableCollection<out Cluster<T>> {
        // 按类别拆分所有POI
        val categoryGroupedItems = items.groupBy { it.category }
        val allClusters = mutableListOf<Cluster<T>>()
        // 每个类别单独执行聚类逻辑
        categoryGroupedItems.values.forEach { categoryItems ->
            val tempAlgorithm = NonHierarchicalDistanceBasedAlgorithm<T>()
            tempAlgorithm.addItems(categoryItems)
            allClusters.addAll(tempAlgorithm.getClusters(zoom))
        }
        return allClusters
    }
}

步骤3:替换ClusterManager的默认算法

val clusterManager = ClusterManager<PoiItem>(localContext, googleMap)
// 替换为自定义按类别聚类算法
clusterManager.algorithm = CategoryClusterAlgorithm()
clusterManager.renderer = PoiClusterRenderer(localContext, googleMap, clusterManager)
clusterManager.addItems(points)
googleMap.setOnCameraIdleListener(clusterManager)

该方案优势:仅需维护一个ClusterManager实例,后续新增POI类别无需修改聚类逻辑,适合类别数量较多的场景。


优化建议

  • 两种方案都可以重写PoiClusterRenderer的onBeforeClusterRendered方法,给不同类别的聚类簇设置对应类别的颜色或图标,提升视觉辨识度。
  • 若使用方案1,需要动态切换某类POI显隐时,仅需要操作对应ClusterManager的clear()/addItems()方法即可,无需全量刷新地图。

内容的提问来源于stack exchange,提问作者susosaurus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 11:15:02