地图投影在非18F缩放级别异常,求无需重复移相机的解决方案
解决方案
问题根源
- 地图未完全初始化时调用投影API:首次调用
centerMap时,Google Maps的Projection对象尚未就绪,导致toScreenLocation返回异常坐标(如日志中的负数值),进而计算出错误的目标经纬度。 - 强制固定缩放级别:每次调用
moveCamera都硬编码缩放级别为18F,不仅破坏原有缩放体验,还会导致投影计算在缩放变化过程中不稳定。 - 偏移计算逻辑错误:原代码中的
length计算逻辑复杂且结果不准确,无法正确将用户位置偏移到抽屉上方的目标区域。
修复步骤
1. 等待地图完全加载后执行首次调整
Google Maps的Projection只有在地图渲染完成后才能正常工作,因此需要监听OnMapLoadedCallback,在地图就绪后再执行首次位置调整:
// 初始化GoogleMap时添加监听 googleMap.setOnMapLoadedCallback { // 传入实际的屏幕高度和抽屉高度 centerMap(screenHeight, drawerHeight) }
2. 优化偏移计算逻辑
重新推导偏移量:我们需要让用户位置的屏幕Y坐标落在抽屉顶部区域的中心,即屏幕总高度减去抽屉高度后的一半。偏移量为目标Y坐标与原中心Y坐标的差值:
fun centerMap(height: Int, drawerHeight: Int) { LocationDataProvider.location?.let { userLocation -> val userLatLng = LatLng(userLocation.lat, userLocation.lng) // 获取用户位置当前的屏幕坐标 val screenPoint = googleMap.projection.toScreenLocation(userLatLng) // 计算目标屏幕Y坐标:抽屉上方区域的垂直中心 val targetScreenY = (height - drawerHeight) / 2 // 计算需要偏移的Y值 val offsetY = targetScreenY - screenPoint.y // 计算调整后的屏幕坐标 val adjustedScreenPoint = Point(screenPoint.x, screenPoint.y + offsetY) // 转换回经纬度 val targetCameraLatLng = googleMap.projection.fromScreenLocation(adjustedScreenPoint) moveCamera(targetCameraLatLng) } }
3. 保留当前缩放级别,避免强制固定
修改moveCamera方法,使用地图当前的缩放级别,而非硬编码的18F,确保投影计算稳定:
fun moveCamera(location: LatLng) { val currentZoom = googleMap.cameraPosition.zoom val cameraUpdate = CameraUpdateFactory.newLatLngZoom(location, currentZoom) googleMap.animateCamera(cameraUpdate) }
4. 避免在相机移动过程中执行投影计算
添加OnCameraIdleListener,确保仅在相机稳定后执行位置调整,防止异步动画导致的投影异常:
private var needAdjustPosition = false // 初始化时设置监听 googleMap.setOnCameraIdleListener { if (needAdjustPosition) { centerMap(screenHeight, drawerHeight) needAdjustPosition = false } } // 需要调整位置时,设置标志位而非直接调用 fun triggerPositionAdjust() { needAdjustPosition = true }
额外注意事项
- 确保
screenHeight是地图容器的实际高度,而非整个屏幕高度(如果地图不是全屏的话)。 - 若需要周期性调整位置(如每5秒),需先检查相机是否处于稳定状态(通过
googleMap.isCameraMoving判断),避免在动画过程中调用投影API。
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

