Jetpack Compose中Google Map收集新LatLng时缩放功能失效如何修复?
问题根因
你的代码触发了地图状态更新死循环:
- 用户操作地图(缩放/平移)后,
setOnCameraIdleListener回调会把当前中心点更新到ViewModel的lastSelectedLocation lastSelectedLocation的收集回调会强制调用moveCamera,用固定的Constants.ZOOM_CAMERA缩放级别把地图定位到新的中心点,直接覆盖了用户刚刚调整的缩放值,所以永远没法缩小- 额外问题:你当前把
isZoomGesturesEnabled设为false,直接禁用了缩放手势,也会导致用户无法手动缩放地图
修复方案
1. 开启缩放手势
把地图UI设置里的isZoomGesturesEnabled改为true,允许用户手动操作缩放:
uiSettings.apply { isMyLocationButtonEnabled = true isZoomControlsEnabled = true isZoomGesturesEnabled = true // 修改此处 }
2. 拆分位置更新的触发场景,避免循环调用
不要只要lastSelectedLocation变化就强制更新相机,只有首次进入页面、用户主动点击定位按钮这类主动触发的场景才移动相机,用户手动拖动/缩放地图触发的位置更新不要反过来再移动相机。
你可以在ViewModel里加一个标记位,区分位置更新的来源:
第一步:修改ViewModel,增加更新类型标记
先定义位置更新来源枚举:
enum class LocationUpdateSource { USER_DRAG, // 用户拖动/缩放地图触发的更新 INITIAL, // 首次页面初始化 USER_CLICK_LOCATION_BUTTON // 用户点击定位按钮触发的更新 }
修改ViewModel的相关逻辑:
// ViewModel中新增更新来源Flow private val _locationUpdateSource = MutableStateFlow(LocationUpdateSource.INITIAL) val locationUpdateSource = _locationUpdateSource.asStateFlow() // 给setLocation方法加来源参数,默认是用户拖动触发 fun setLocation(loc: LocationModel, source: LocationUpdateSource = LocationUpdateSource.USER_DRAG) { _lastSelectedLocation.value = loc _locationUpdateSource.value = source } // 用户点击定位按钮的场景,传入对应来源 private fun getCurrentLocation(context: Context) { // 原有逻辑不变 val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context) try { val locationResult = fusedLocationProviderClient.lastLocation locationResult.addOnCompleteListener { task -> if (task.isSuccessful) { task.result?.let { setLocation( LocationModel(it.latitude, it.longitude), source = LocationUpdateSource.USER_CLICK_LOCATION_BUTTON ) } } else { Log.d("Exception", " Current User location is null") } } } catch (e: SecurityException) { Log.d("Exception", "Exception: $e.message.toString()") } }
第二步:修改地图侧的收集逻辑,过滤用户拖动触发的更新
scope.launch { // 合并位置和更新来源两个Flow combine(navigatorViewModel.lastSelectedLocation, navigatorViewModel.locationUpdateSource) { loc, source -> loc to source }.collect { (loc, source) -> // 仅非用户拖动触发的更新,才执行移动相机逻辑 if (source != LocationUpdateSource.USER_DRAG) { val position = LatLng(loc.lat, loc.lng) moveCamera( CameraUpdateFactory.newLatLngZoom( position, Constants.ZOOM_CAMERA ) ) } } } // 拖动地图触发的位置更新,传入用户拖动来源标记 setOnCameraIdleListener { val cameraPosition = map.cameraPosition setLocation( LocationModel( lat = cameraPosition.target.latitude, lng = cameraPosition.target.longitude ), source = LocationUpdateSource.USER_DRAG ) }
可选优化
如果你希望主动移动相机的时候也沿用用户之前调整的缩放级别,而不是固定用Constants.ZOOM_CAMERA,可以把当前缩放值也同步存储到ViewModel里,移动相机的时候读取存储的缩放值即可。
内容的提问来源于stack exchange,提问作者Saeed Noshadi
相关产品推荐
相关产品推荐

