【问题标题】:Adding gesture recognizers in MGLAnnotationImage?在 MGLAnnotationImage 中添加手势识别器?
【发布时间】:2021-04-17 21:31:50
【问题描述】:

这是我的 imageFor Mapbox 函数:

func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? {
        var reuseid = ""
        switch annotation.subtitle ?? "" {
        case "uno":
            reuseid = "uno"
        case "dos":
            reuseid = "dos"
        case "tres":
            reuseid = "tres"
        default:
            reuseid = "default"
        }
        var annotationImage = mapView.dequeueReusableAnnotationImage(withIdentifier: reuseid)
        
        if annotationImage == nil {
            guard let image = UIImage(named: reuseid) else { return nil }
            annotationImage = MGLAnnotationImage(image: image, reuseIdentifier: reuseid)
            let tapGesture = AnnotationTapGestureRecognizer(target: self, action: #selector(Coordinator.tappedAnnotation(sender:)))
            tapGesture.annotation = annotation as! MGLPointAnnotation
            annotationImage.addGestureRecognizer(tapGesture) //error on this line says 'Value of type 'MGLAnnotationImage?' has no member 'addGestureRecognizer''
        }
        return annotationImage
    }

class AnnotationTapGestureRecognizer: UITapGestureRecognizer {
    var annotation = MGLPointAnnotation()
}

如何制作,以便将手势识别器添加到要返回的 annotationImage 中?

【问题讨论】:

    标签: swift mapbox uigesturerecognizer gesture uitapgesturerecognizer


    【解决方案1】:

    返回MGLAnnotationView,而不是返回MGLAnnotationImage,它只是UIView 的子类。您可以为其附加手势识别器。

    为了简化事情,让我们继承MGLAnnotationView 并创建我们的自定义标记。这个标记没什么特别的,只是一个图像(50 x 50 点),当然可以用我们的自定义识别器点击。为此,我只是有效地将标记设为UIButton。当用户点击此标记时,该标记将调用委托上的didSelectMarker(point:) 方法。

    class XAnnotationView: MGLAnnotationView {
        weak var delegate: XMapMarkerDelegate?
        var point: MGLPointAnnotation?
    
        required override init(reuseIdentifier: String?) {
            super.init(reuseIdentifier: reuseIdentifier)
            let rect = CGRect(x: 0, y: 0, width: 50, height: 50)
            let button = UIButton(frame: rect)
            let image = UIImage(named: "mapMarker")
    
            button.setImage(image, for: .normal)
            button.setImage(image, for: .selected)
            button.setImage(image, for: .highlighted)
            button.imageView?.contentMode = .scaleAspectFit
            button.addTarget(self, action: #selector(markerAction), for: .touchUpInside)
            frame = rect
            addSubview(button)
            isEnabled = false // disable it if we're adding our own gesture recognizer
        }
    
        required init?(coder: NSCoder) {
            return nil
        }
    
        @objc private func markerAction() {
            delegate?.didSelectMarker(point: point)
        }
    }
    

    XMapMarkerDelegate 委托是我们刚刚创建的,所以让我们通过创建一个任何类对象都可以遵循的协议来定义它,可能是一个UIViewController,来处理这个方法。任何符合此协议的视图控制器现在都可以处理这些点击事件。

    protocol XMapMarkerDelegate: AnyObject {
        func didSelectMarker(point: MGLPointAnnotation)
    }
    

    然后,无论哪个类对象显示我们的地图,可能是UIViewController,使其符合我们的自定义协议并处理触摸事件。该对象可能与地图的委托对象相同,因此我们将它们组合在一起以进行更整洁的组织:

    extension SomeViewController: MGLMapViewDelegate, XMapMarkerDelegate {
        /* This is one of Mapbox's many delegate methods.
           This method is for adding annotation views to the map. */
        func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
            if annotation is MGLPointAnnotation { // only handle point annotations
                if let reusable = dequeueReusableAnnotationView(withIdentifier: "marker") as? XAnnotationView { // find a reusable marker if one is available with the given identifier
                    reusable.point = annotation // assign this marker the current point
                    return reusable
                } else { // if no reusable marker found, create a new marker with the given identifier
                    let new = XAnnotationView(reuseIdentifier: "marker")
                    new.delegate = self // assign self as the delegate
                    new.point = annotation // assign this marker the current point
                    return new
                }
            } else {
                return nil
            }
        }
        
        /* This is our custom delegate method. */
        func didSelectMarker(point: MGLPointAnnotation) {
            print("did tap marker")
        }
    }
    

    您可以根据需要向标记添加自定义数据或对象来对其进行自定义。您可以创建注释视图的多个子类,每个子类具有不同的大小或图像,并根据注释点在地图上使用不同的子类。可能性几乎是无限的。

    【讨论】:

    • 我想我可能不得不返回 MGLAnnotationImage,因为 imageFor 函数内置于 Mapbox 的协调器委托协议中。您是否有过去对您有用的具体实施?
    • 如果您愿意,我可以发布一些代码,但 Mapbox 有一个专门用于返回 MGLAnnotationView 的委托方法,因此您可以使用它来代替您当前使用的那个。它们的工作方式相同,一个只处理图像和其他视图。
    • 如果我尝试将 imageFor 中的代码放入 viewFor 中,我会收到一条错误消息,提示“无法转换 'MGLAnnotationImage 类型的返回表达式?”返回类型 'MGLAnnotationView?'"...我知道这是因为我明确地初始化了 MGLAnnotationImage 的实例,但我这样做是因为它具有我的自定义注释图像所需的图像的关键属性.. .如果您添加一些代码,它可能会帮助将来遇到相同问题的其他人:)
    • Mapbox 为自定义地图数据推荐自定义标记,我们正在使用自定义注释视图,但您可以从 Mapbox 下载它们并将它们添加到您的资产目录docs.mapbox.com/help/getting-started/add-markers
    • 旁注:如果您不擅长创建自定义资源,请考虑在线寻找免费的 PNG 地图标记。
    猜你喜欢
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多