【问题标题】:iOS SwiftUI: How to detect location of UITapGesture on view?iOS SwiftUI:如何在视图中检测 UITapGesture 的位置?
【发布时间】:2021-05-22 11:23:56
【问题描述】:

所以我正在使用 Mapbox。 map 结构符合 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 时会导致应用程序崩溃--如果我删除参数,那么至少可以正确调用该函数而不会崩溃。请帮忙

【问题讨论】:

  • 您从崩溃中得到什么错误/堆栈跟踪?我不知道 Mapbox,但我会从 tappedMap 内的断点开始,然后检查那里接收到的对象。
  • @JohnNimis 我不知道 Xcode 中的堆栈跟踪在哪里......对不起这里的新手 - 抛出的错误说 Thread 1: ........ :无法识别的选择器发送到实例,然后是我认为的内存地址。这让我相信它没有收到 UITapGestureRecognizer 而是其他东西,对吗?此外,如果我在方法的第一行设置断点(当我将第一行设置为打印语句时),仍然会引发错误,因此它与 tappedMap 函数正在接收的内容或它的调用方式有关
  • 好的,我正在尝试重现该错误,但我得到一堆编译器错误:一个是“类'Map.Coordinator'没有初始化程序”,另一个必须做使用 mapView 属性,该属性未在您的代码示例中声明。另外,您是否在这些文件中导入了 MapKit?您可能会考虑以不同的方式命名您的 Map 结构,以防出现某种命名空间冲突。
  • 这不是 MapKit,这是 MapBox,你需要一个 pod 文件来导入正确的 cocoapods
  • 是的,我知道,我已经导入了 Mapbox。我问是因为 MapKit 还定义了一个名为 Map 的结构。我只是注意到这一点,因为我的示例项目已经在不同的文件中有一些 MapKit 代码。

标签: swift swiftui mapbox uitapgesturerecognizer uiviewrepresentable


【解决方案1】:

好的,第一个问题是您在 tapGesture 声明中的选择器定义。改成这样:

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

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

将自己的手势识别器添加到 MGLMapView 将阻止 MGLMapView 内置相应的手势识别器。避免 冲突,定义哪个手势优先。

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

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)
}

【讨论】:

  • 这就是我认为的 tappedMap 函数的意思(不过,我对@objc 函数的看法一般是不确定的)。但是,当我点击 mapView 时,我收到一个线程错误,上面写着“无法识别的选择器已发送到实例”。我也即将更新我的原始答案,因为我认为您还需要包含 updateUIView() 函数以使其编译...
  • @nickcoding 我更新了我的答案,并且能够验证它是否解决了问题
  • 它检测到点击在屏幕上的位置,但我试图在此处模仿最佳答案:stackoverflow.com/questions/34431459/… 人们点击视图的位置,并且点击转换为所在位置的纬度和经度tap 是-我认为这就是 .convert() 函数所做的,但我认为您设置坐标集的方式只是将一个视图中屏幕上的位置转换为包含视图中的相同位置
  • 啊,我明白了!这很酷。在这种情况下,第二行应该是:let coordinateSet = control.mapView.convert(locationInMap, toCoordinateFrom: control.mapView)
  • 这很有魅力,非常感谢! (我会尽可能奖励赏金)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-24
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 2019-10-22
  • 1970-01-01
  • 2022-11-23
相关资源
最近更新 更多