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

MKUserTrackingButton无定位权限时显示spinner问题求助

解决MKUserTrackingButton权限不足时持续旋转的问题

我之前也踩过这个坑——MKUserTrackingButton在用户拒绝定位权限或者权限未确定时,会一直显示旋转的活动指示器,完全没法恢复到默认的指南针图标,而且它还不是UIButton子类,连加点击事件都做不了。下面分享几个亲测有效的解决思路:

思路1:监听权限状态,动态切换按钮显示

核心思路是不让MKUserTrackingButton在权限不足的情况下处于活跃状态,具体步骤:

  • 初始化CLLocationManager,并监听定位权限变化的通知:
    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 监听权限变化通知
        NotificationCenter.default.addObserver(self, selector: #selector(handleAuthorizationChange), name: NSNotification.Name.CLLocationManagerDidChangeAuthorization, object: nil)
        // 初始检查权限状态
        handleAuthorizationChange()
    }
    
    @objc private func handleAuthorizationChange() {
        let status = locationManager.authorizationStatus
        let isAuthorized = status == .authorizedWhenInUse || status == .authorizedAlways
        
        if isAuthorized {
            // 权限足够,显示原生按钮
            userTrackingButton.isHidden = false
            customPermissionButton.isHidden = true
        } else {
            // 权限不足,隐藏原生按钮,显示自定义引导按钮
            userTrackingButton.isHidden = true
            customPermissionButton.isHidden = false
        }
    }
    
  • 自定义的customPermissionButton可以做成和原生按钮一致的外观,点击时触发权限请求或者引导用户去设置:
    @objc private func onCustomButtonTap() {
        let status = locationManager.authorizationStatus
        if status == .notDetermined {
            // 还未请求过权限,触发系统权限弹窗
            locationManager.requestWhenInUseAuthorization()
        } else {
            // 已拒绝权限,引导用户前往设置页开启
            guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return }
            UIApplication.shared.open(settingsURL)
        }
    }
    

思路2:完全自定义替代按钮,彻底掌控行为

如果不想依赖原生按钮的不可控行为,直接自己做一个模仿MKUserTrackingButton外观的UIButton,完全自定义逻辑:

  • 从系统SF Symbols中选取类似图标(比如location.circle.fill或compass系列),还原原生按钮的视觉风格
  • 给按钮添加点击事件,先检查权限再执行对应逻辑:
    let customTrackingButton = UIButton(type: .system)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        customTrackingButton.setImage(UIImage(systemName: "location.circle.fill"), for: .normal)
        customTrackingButton.addTarget(self, action: #selector(onCustomTrackingTap), for: .touchUpInside)
        mapView.addSubview(customTrackingButton)
        // 布局按钮到地图右上角,和原生位置保持一致
    }
    
    @objc private func onCustomTrackingTap() {
        let status = locationManager.authorizationStatus
        guard status == .authorizedWhenInUse || status == .authorizedAlways else {
            // 权限不足,弹出提示引导用户
            let alert = UIAlertController(title: "需要定位权限", message: "请开启定位权限以使用位置跟踪功能", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in
                guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { return }
                UIApplication.shared.open(settingsURL)
            })
            alert.addAction(UIAlertAction(title: "取消", style: .cancel))
            present(alert, animated: true)
            return
        }
        // 权限足够,触发地图位置跟踪
        mapView.setUserTrackingMode(.follow, animated: true)
    }
    

这种方式完全不会出现 spinner 一直转的问题,还能和苹果地图的交互体验保持一致。

思路3:不推荐的私有API方案(谨慎使用)

如果非要坚持用原生按钮,有人尝试过用KVO监听按钮的内部状态,但这属于私有API范畴,苹果可能会拒绝审核,仅做参考:

  • 监听MKUserTrackingButton的_state属性,当状态变为加载时强制恢复图标,但这种方法随时可能失效,不建议在正式项目中使用。

内容的提问来源于stack exchange,提问作者Mischa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:41:08