iOS SwiftUI:如何检测视图中 UITapGesture 的位置?

iOS SwiftUI: How to detect location of UITapGesture on view?

所以我正在使用 Mapbox。地图结构符合 UIViewRepresentable 协议。在我的 makeUIView() 函数中,我创建了一个点击手势识别器并将其添加到地图视图中。

struct Map: UIViewRepresentable {

    private let mapView: MGLMapView = MGLMapView(frame: .zero, styleURL: MGLStyle.streetsStyleURL)

    func makeUIView(context: UIViewRepresentableContext<Map>) -> MGLMapView {
        mapView.delegate = context.coordinator
        let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: Selector("tappedMap"))
        mapView.addGestureRecognizer(gestureRecognizer)
        return mapView
    }

    func updateUIView(_ uiView: MGLMapView, context: UIViewRepresentableContext<Map>) {
        print("Just updated the mapView")
    }

    func makeCoordinator() -> Map.Coordinator {
        Coordinator(appState: appState, self)
    }

    // other functions that make the struct have functions required by Mapbox 

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

    final class Coordinator: NSObject, MGLMapViewDelegate {
        var control: Map

        //a bunch of delegate functions

        @objc func tappedMap(sender: UITapGestureRecognizer) {
            let locationInMap = sender.location(in: control)
            let coordinateSet = sender.convert(locationInMap, toCoordinateFrom: control)
        }
    }
}

tappedMap 函数中的任何一行都无法正确编译...此外,当我在 tappedMap 的参数中包含 'sender: UITapGestureRecognizer' 时,我会在点击 mapView 时导致应用程序崩溃——如果我删除参数,那么该函数至少可以正确调用而不会崩溃。请帮助

好的,第一个问题是您在 tapGesture 声明中的选择器定义。将其更改为:

let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.tappedMap(sender:)))

此外,您需要管理手势识别器的优先级,因为 MGLMapView 在内部包含 UIGestureRecognizer 逻辑。我找到了 here:

的讨论

Adding your own gesture recognizer to MGLMapView will block the corresponding gesture recognizer built into MGLMapView. To avoid conflicts, define which gesture takes precedence.

您可以在您的项目中尝试此代码(几乎只是从上面的链接页面复制而来)编辑:我需要更改原始答案中的行顺序:

let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: Selector("tappedMap"))

// HERE'S THE NEW STUFF:
for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
    gestureRecognizer.require(toFail: recognizer)
}

mapView.addGestureRecognizer(gestureRecognizer)

编辑:我能够测试这个。

我对你的 tappedMap 选择器内部的逻辑有点困惑:也许你的意思是这样的?

@objc func tappedMap(sender: UITapGestureRecognizer) {
    let locationInMap = sender.location(in: control.mapView)
    let coordinateSet = sender.view?.convert(locationInMap, to: control.mapView)
}