Как правило, вы добавляете, например, rightCalloutAccessoryView
, а затем внедряете calloutAccessoryControlTapped
, как показано в , как сделать выноску с аннотацией с помощью пин-кода?
Но вы говорите:
Мне нужно сделать весь выносной элемент интерактивным
В MapKit нет метода делегата для захвата нажатий на выноску, только на дополнительные представления.Но вы можете добавить свой собственный делегат, чтобы сделать это для вас.
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!)
}
}
Затем в iOS 11 и более поздних версиях вы можете зарегистрировать этот reuseIdentifier:
override func viewDidLoad() {
super.viewDidLoad()
mapView.register(CustomAnnotationView.self,
forAnnotationViewWithReuseIdentifier: CustomAnnotationView.preferredReuseIdentifier)
}
И ваш viewFor
может указать делегата:
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
}
}
Или, если вам нужно поддерживать версии iOS до 11, вы не зарегистрируете идентификатор повторного использования, но вам придется вручную создавать экземпляр CustomAnnotationView
, если он не был успешно удален из очереди:
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
}
}
В любом случаеТеперь вы можете настроить контроллер представления на новый CustomAnnotationViewDelegate
:
extension ViewController: CustomAnnotationViewDelegate {
func didTapCallout(for annotation: MKAnnotation) {
print("tapped callout for \(annotation)")
}
}
Но обратите внимание, что в приведенном выше описании я добавляю распознаватель жестов касания в методе CustomAnnotationView
init
,чтобы гарантировать, что жест касания создается один и только один раз, когда представление аннотации создается впервые.