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
相关产品推荐
相关产品推荐

