自定义标注视图按钮映射

Custom Callout View Button to Map

我在 MapView 上工作,点击任何自定义注释图钉,我会显示自定义标注视图(从 xib 文件加载)。

从这个自定义标注我有一个 UIButton,我已经可以检测到点击这个按钮但我想在地图上访问像基本标注中的 : view?.rightCalloutAccessoryView。

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView,  {

    if view.annotation!.isKind(of: MKUserLocation.self){
        return
    }

    let customView = (Bundle.main.loadNibNamed("CustomCalloutView", owner: self, options: nil))?[0] as! CustomCalloutView;
    let calloutViewFrame = customView.frame;
    customView.frame = CGRect(x: -calloutViewFrame.size.width/2.23, y: -calloutViewFrame.size.height+10, width: 315, height: 170)

    view.addSubview(customView)

    let region = MKCoordinateRegion(center: pinToZoomOn!.coordinate, span: span)

    mapView.setRegion(region, animated: true)
}

路线是根据经典标注正确计算出来的,但我不知道如何通过自定义标注的按钮访问我的地图。

我的 CustomCalloutViewClass :

import UIKit
import MapKit

class CustomCalloutView: MKAnnotationView {

@IBOutlet weak var goButton: UIButton!

@IBAction func goButton(_ sender: AnyObject) {
    print("Button clicked sucessfully")
}

// MARK: - Detect taps on callout

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let hitView = super.hitTest(point, with: event)
    if hitView != nil {
        superview?.bringSubview(toFront: self)
    }
    return hitView
}

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    let rect = self.bounds
    var isInside = rect.contains(point)
    if !isInside {
        for view in subviews {
            isInside = view.frame.contains(point)
            if isInside {
                break
            }
        }
    }
    return isInside
}
}

如果有人有想法,那将对我有所帮助。我被困在这个问题上。

提前致谢。

选项 1:在传递给 CustomCalloutView 的闭包中捕获 MKMapView 实例

添加将在按钮操作上调用的闭包。闭包将捕获 MKMapView 实例,您将能够看到我们在里面。

class CustomCalloutView: MKAnnotationView {
    var didTapGoButton: (() -> Void)?

    @IBAction func goButton(_ sender: AnyObject) {
        didTapGoButton?()
    }
}

选项 2:添加对 MKMapView 的弱引用作为标注的 属性

这不是一个干净的解决方案,但在某些情况下它可能是一个选择。您只需创建一个弱 属性 存储对 MKMapView 实例的引用 CustomCalloutView

class CustomCalloutView: MKAnnotationView {
    weak var mapView: MKMapView?
}

配置

这就是为这两种解决方案连接 CustomCalloutView 的方法。请记住使用 swift 捕获列表来捕获对 MKMapView 实例的弱引用。没有它,您可能会创建一个强大的参考循环。

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView)  {
    // ...
    let customView = (Bundle.main.loadNibNamed("CustomCalloutView", owner: self, options: nil))?[0] as! CustomCalloutView;
    // Option 1
    customView.didTapGoButton = { [weak mapView ] in 
        print(mapView?.annotations.count) 
    }
    // Option 2
    customView.mapView = mapView
    // ...
}

非常感谢您的帮助!

我使用第一个选项来捕获 MKMapView 实例。

如果有人遇到同样的问题,您可以使用第一个选项并将其添加到您的 didSelect MapView 函数中:

let selectedLoc = view.annotation
print("Annotation '\(String(describing: selectedLoc?.title!))' has been selected")

let location = view.annotation as! YourCustomClassType
let launchOptions = [MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving]
customView.didTapGoButton = { location.mapItem().openInMaps(launchOptions: launchOptions) }

谢谢

var didTapGoButton: (() -> Void)?这种类型的闭包对于通过 mkmapview 中调用布局视图中的按钮操作从视图导航到 viewControllers 非常有帮助。