0

I need to click on annotation on the map. I can see selected annotation view like this mkannotationview

I want to add click listener on this selected annotation view to open another view controller with annotation's details. How can I do this?

func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    if let selected = (view.annotation as? CustomAnnotation) {
        self.selectedAnnotation = selected
    }
}

Edited

Vladislav
  • 273
  • 3
  • 15

1 Answers1

1

Generally you’d add, for example, a rightCalloutAccessoryView and then implement calloutAccessoryControlTapped, like shown in how do I make a pin annotation callout?

But you say:

I need to make the whole callout clickable

MapKit doesn’t have a delegate method to capture taps on the callout, itself, only on the accessory views. But you can add your own delegate to do this for you.

protocol CustomAnnotationViewDelegate: class {
    func didTapCallout(for annotation: MKAnnotation)
}

class CustomAnnotationView: MKPinAnnotationView {
    static let preferredReuseIdentifier = Bundle.main.bundleIdentifier! + ".customAnnotationView"

    weak var delegate: CustomAnnotationViewDelegate?

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)

        canShowCallout = true

        let tap = UITapGestureRecognizer(target: self, action: #selector(didTapAnnotationView(_:)))
        self.addGestureRecognizer(tap)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc func didTapAnnotationView(_ gesture: UITapGestureRecognizer) {
        let location = gesture.location(in: self)

        // ignore taps on the annotation view, itself

        if bounds.contains(location) { return }

        // if we got here, we must have tapped on the callout

        delegate?.didTapCallout(for: annotation!)
    }
}

Then in iOS 11 and later, you can register this reuseIdentifier:

override func viewDidLoad() {
    super.viewDidLoad()

    mapView.register(CustomAnnotationView.self,
                     forAnnotationViewWithReuseIdentifier: CustomAnnotationView.preferredReuseIdentifier)
}

And your viewFor could specify the delegate:

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        if annotation is MKUserLocation { return nil }

        let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier, for: annotation) as! CustomAnnotationView
        annotationView.delegate = self
        return annotationView
    }
}

Or, if you need to support iOS versions prior to 11, you wouldn’t register the reuse identifier but would have to manually instantiate the CustomAnnotationView yourself if it is not successfully dequeued:

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        if annotation is MKUserLocation { return nil }

        var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: CustomAnnotationView.preferredReuseIdentifier) as? CustomAnnotationView
        if annotationView == nil {
            annotationView = CustomAnnotationView(annotation: annotation, reuseIdentifier: CustomAnnotationView.preferredReuseIdentifier)
            annotationView?.delegate = self
        } else {
            annotationView?.annotation = annotation
        }

        return annotationView
    }
}

Either way, you can now have your view controller conform to the new CustomAnnotationViewDelegate:

extension ViewController: CustomAnnotationViewDelegate {
    func didTapCallout(for annotation: MKAnnotation) {
        print("tapped callout for \(annotation)")
    }
}

But note that in the above, I’m adding the tap gesture recognizer in the CustomAnnotationView init method, to ensure that the tap gesture is created once and only once, when the annotation view is first created.

Rob
  • 415,655
  • 72
  • 787
  • 1,044