Android Google Maps Compose如何同时显示多个InfoWindow
解决Google Maps Compose同时显示多个InfoWindow的问题
Google Maps(包括其Compose封装库)的原生InfoWindow机制默认只支持同时显示一个窗口。你调用多个markerState.showInfoWindow()时,会触发内部状态冲突,导致系统反复切换显示状态,最终引发重绘风暴和OOM。
要实现同时显示多个信息窗口,只能通过自定义Compose组件模拟InfoWindow的方式来实现,绕过原生的限制。具体方案如下:
核心思路
放弃使用官方的MarkerInfoWindow,改用普通Marker标记位置,再在地图上层叠加自定义的可组合控件作为信息窗口,通过地图投影(Projection)将地理坐标(LatLng)转换为屏幕坐标,实现窗口与Marker的位置绑定。
代码实现示例
1. 定义自定义InfoWindow组件
@Composable fun CustomInfoWindow( modifier: Modifier = Modifier, markerPosition: LatLng, mapProjection: Projection?, content: @Composable () -> Unit ) { mapProjection?.let { projection -> // 将地理坐标转换为屏幕坐标 val screenCoords = projection.toScreenLocation(markerPosition) Box( modifier = modifier .offset( // 根据Marker图标和窗口大小调整偏移,确保窗口对齐Marker顶部 x = (screenCoords.x - 75).dp, y = (screenCoords.y - 140).dp ) .background(Color.White, RoundedCornerShape(8.dp)) .padding(horizontal = 12.dp, vertical = 8.dp) .shadow(elevation = 4.dp, shape = RoundedCornerShape(8.dp)) ) { content() } } }
2. 在地图中使用自定义窗口
Box(modifier = Modifier.fillMaxSize()) { val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(someLocation, 15f) } // 保存地图投影,用于坐标转换 var mapProjection by remember { mutableStateOf<Projection?>(null) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState, // 地图加载完成后获取初始投影 onMapLoaded = { map -> mapProjection = map.projection }, // 地图移动过程中更新投影 cameraMoveStartedListener = { mapProjection = cameraPositionState.projection }, // 地图停止移动后更新投影 cameraIdleListener = { mapProjection = cameraPositionState.projection } ) { // 添加普通Marker,仅用于显示图标 Marker( state = rememberMarkerState(position = someLocation), icon = BitMapUtils.bitmapDescriptor(context, R.drawable.ic_own_position) ) Marker( state = rememberMarkerState(position = someLocation2), icon = BitMapUtils.bitmapDescriptor(context, R.drawable.ic_own_position) ) } // 叠加两个自定义信息窗口 CustomInfoWindow( markerPosition = someLocation, mapProjection = mapProjection ) { Text("Test 1") } CustomInfoWindow( markerPosition = someLocation2, mapProjection = mapProjection ) { Text("Test 2") } }
注意事项
- 偏移量(
x/y的数值)需要根据你的Marker图标尺寸、自定义窗口的大小自行调整,确保窗口刚好显示在Marker的正上方或指定位置。 - 监听地图的
cameraMoveStarted和cameraIdle事件,保证地图移动/缩放时,窗口位置能实时更新。 - 如果需要实现点击Marker显示/隐藏窗口的逻辑,可以给Marker添加
onClick回调,维护一个布尔状态变量来控制自定义窗口的显示与否。
内容的提问来源于stack exchange,提问作者PioSwi
相关产品推荐
相关产品推荐

