无法将点击手势识别器添加到 SwiftUI MKMapView UIViewRepresentable

Can't add Tap Gesture Recognizer to SwiftUI MKMapView UIViewRepresentable

我有一个带有 SwiftUI 生命周期的 SwiftUI 应用程序,我正在尝试使用点击手势来 在 MKMapView 中工作。我似乎无法正确获取对地图的引用。我都 想要在本小节中做的是点击地图并添加注释。那时我会 也使用注释的坐标。

这是代码。

struct MapView: UIViewRepresentable {

    typealias UIViewType = MKMapView
    @State private var myMapView: MKMapView?

    class Coordinator: NSObject, MKMapViewDelegate {
        var control: MapView
        let parent = MapView()
    
        let sfCoord = CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194)

        init(_ control: MapView) {
            self.control = control
        }
    
        func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
            if let annotationView = views.first {
                if let annotation = annotationView.annotation {
                    if annotation is MKUserLocation {
                        let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 2000, longitudinalMeters: 2000)
                        mapView.setRegion(region, animated: true)
                    }
                }
            }
        }//did add
    
        @objc func addAnnotationOnTapGesture(sender: UITapGestureRecognizer) {
            if sender.state == .ended {
                print("in addAnnotationOnTapGesture")
                let point = sender.location(in: parent.myMapView)
                print("point is \(point)")
                let coordinate = parent.myMapView?.convert(point, toCoordinateFrom: parent.myMapView)
                print("coordinate?.latitude is \(String(describing: coordinate?.latitude))")
                let annotation = MKPointAnnotation()
                annotation.coordinate = coordinate ?? sfCoord
                annotation.title = "Start"
                parent.myMapView?.addAnnotation(annotation)
            }
        }
    }//coord

    func makeUIView(context: Context) -> MKMapView {
        let map = MKMapView()
        map.showsUserLocation = true
        map.delegate = context.coordinator
    
        DispatchQueue.main.async {
            self.myMapView = map
        }
    
        let gRecognizer = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.addAnnotationOnTapGesture(sender:)))
        map.addGestureRecognizer(gRecognizer)

        return map
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func updateUIView(_ uiView: MKMapView, context: Context) {

    }
}//struct MapView

和 LocationManager 供参考:

class LocationManager: NSObject, ObservableObject {
    private let locationManager = CLLocationManager()
    @Published var location: CLLocation? = nil

    override init() {
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.distanceFilter = kCLDistanceFilterNone
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    }
}

extension LocationManager: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        print(status)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
    
        self.location = location
    }
}//extension

最后是 ContentView:

struct ContentView: View {

    @ObservedObject var locationManager = LocationManager()

    var body: some View {
        MapView()
    }
}

点击地图会显示如下控制台输出:

在添加AnnotationOnTapGesture

点是 (156.0, 515.6666564941406)

坐标?.纬度为零

如有任何指导,我们将不胜感激。 Xcode 12.5 iOS 14.5

在您的 Coordinator 中,您有两个对 MapView 的引用。一个 (control) 在 init 中设置,代表您想要的实际视图。另一个 (parent) 在您的 Coordinator 中定义,实际上并不是视图层次结构的一部分。因此,当您尝试从中获取坐标时,它会 returns nil。您可以将所有引用更改为 control 并且它有效:

class Coordinator: NSObject, MKMapViewDelegate {
    var control: MapView

    let sfCoord = CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194)

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

    func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
        if let annotationView = views.first {
            if let annotation = annotationView.annotation {
                if annotation is MKUserLocation {
                    let region = MKCoordinateRegion(center: annotation.coordinate, latitudinalMeters: 2000, longitudinalMeters: 2000)
                    mapView.setRegion(region, animated: true)
                }
            }
        }
    }//did add

    @objc func addAnnotationOnTapGesture(sender: UITapGestureRecognizer) {
        if sender.state == .ended {
            print("in addAnnotationOnTapGesture")
            let point = sender.location(in: control.myMapView)
            print("point is \(point)")
            let coordinate = control.myMapView?.convert(point, toCoordinateFrom: control.myMapView)
            print("coordinate?.latitude is \(String(describing: coordinate?.latitude))")
            let annotation = MKPointAnnotation()
            annotation.coordinate = coordinate ?? sfCoord
            annotation.title = "Start"
            control.myMapView?.addAnnotation(annotation)
        }
    }
}//coord