MKMapView userTrackingMode 在 SwiftUI 中重置

MKMapView userTrackingMode reset in SwiftUI

我在 userTrackingMode 设置为 .follow 的 SwiftUI 中显示 MKMapView 时遇到问题。我正在显示一张地图:

struct ContentView: View {
    var body: some View {
        MapView()
    }
}

在这个 MapView 中,我 (a) 设置 userTrackingMode 和 (b) 确保我有使用时权限。我一直在基于故事板的项目中使用这种模式。无论如何,MapView 现在看起来像:

final class MapView: UIViewRepresentable {
    private lazy var locationManager = CLLocationManager()

    func makeUIView(context: Context) -> MKMapView {
        if CLLocationManager.authorizationStatus() == .notDetermined {
            locationManager.requestWhenInUseAuthorization()
        }

        let mapView = MKMapView()
        mapView.showsUserLocation = true
        mapView.userTrackingMode = .follow  // no better is mapView.setUserTrackingMode(.follow, animated: true)
        return mapView
    }

    func updateUIView(_ uiView: UIViewType, context: Context) {
        print(#function, uiView.userTrackingMode)
    }
}

此处一切看起来都不错,但地图(在模拟器和物理设备上)实际上并未处于关注用户跟踪模式。

所以,我在上面进行了扩展,添加了一个采用MKMapViewDelegate协议的协调器,这样我就可以看到跟踪模式发生了什么:

final class MapView: UIViewRepresentable {
    private lazy var locationManager = CLLocationManager()

    func makeUIView(context: Context) -> MKMapView {
        if CLLocationManager.authorizationStatus() == .notDetermined {
            locationManager.requestWhenInUseAuthorization()
        }

        let mapView = MKMapView()
        mapView.delegate = context.coordinator
        mapView.showsUserLocation = true
        mapView.userTrackingMode = .follow  // no better is mapView.setUserTrackingMode(.follow, animated: true)
        return mapView
    }

    func updateUIView(_ uiView: UIViewType, context: Context) {
        print(#function, uiView.userTrackingMode)
    }

    func makeCoordinator() -> MapViewCoordinator {
        return MapViewCoordinator(self)
    }
}

class MapViewCoordinator: NSObject {
    var mapViewController: MapView

    var token: NSObjectProtocol?

    init(_ control: MapView) {
        self.mapViewController = control
    }
}

extension MapViewCoordinator: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, didChange mode: MKUserTrackingMode, animated: Bool) {
        print(#function, mode)
    }
}

这导致:

mapView(_:didChange:animated:) MKUserTrackingMode.follow
updateUIView(_:context:) MKUserTrackingMode.follow
mapView(_:didChange:animated:) MKUserTrackingMode.none

正在将 userTrackingMode 重置为 .none

为了咯咯笑和咧嘴笑,我尝试重置 userTrackingMode,但也好不到哪儿去:

func updateUIView(_ uiView: UIViewType, context: Context) {
    print(#function, uiView.userTrackingMode)
    uiView.userTrackingMode = .follow
}

虽然这个笨拙的模式确实有效:

func updateUIView(_ uiView: UIViewType, context: Context) {
    print(#function, uiView.userTrackingMode)
    DispatchQueue.main.async {
        uiView.userTrackingMode = .follow
    }
}

或者在这个初始过程之后重置 userTrackingMode 的任何东西似乎也有效。

我在 UIViewRepresentable 上做错了吗? MKMapView 中的错误?


这不是很相关,但这是我显示跟踪模式的例程:

extension MKUserTrackingMode: CustomStringConvertible {
    public var description: String {
        switch self {
        case .none:              return "MKUserTrackingMode.none"
        case .follow:            return "MKUserTrackingMode.follow"
        case .followWithHeading: return "MKUserTrackingMode.followWithHeading"
        @unknown default:        return "MKUserTrackingMode unknown/default"
        }
    }
}

令人恼火的是,在花费大量时间调试、准备问题等之后,如果您在初始化期间不提供 frame,这种奇怪的行为似乎只会出现:

let mapView = MKMapView()

当我使用以下内容时(即使最终地图不是这个大小),它也能正常工作:

let mapView = MKMapView(frame: UIScreen.main.bounds)

我仍然post希望它能将其他人从这场噩梦中拯救出来。