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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 23:06:02