Kevin Kevin - 1 year ago 84
Swift Question

Swift 3.0 Map viewForAnnotation Not Outputting Proper Callout

I am having trouble understanding the code for viewForAnnotation method and when it is called. My intention is to display a specific callout depending on what color the pin color is. Upon first loading the mapView, the callouts are displayed properly, however after switching view controllers, the callout buttons are not properly displayed according to the pin color. I have a hunch this might have something to do with when viewForAnnotation is called (whether it is called every time the map appears). I am unable to figure out what is wrong because I am not sure what each part of the code does.

func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

if (annotation is MKUserLocation) {

return nil
}

let identifier = "pinAnnotation"


// In particular I am not sure what the code below does

if let pin = annotation as? ColorPointAnnotation {


if let view = map.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView {
view.annotation = annotation
view.pinTintColor = pin.color ?? .purple

return view

} else {

let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view.isEnabled = true

view.canShowCallout = true

view.pinTintColor = pin.color ?? .purple

let btn = UIButton(type: .detailDisclosure)
view.rightCalloutAccessoryView = btn


if view.pinTintColor == .red || view.pinTintColor == .green {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
button.setBackgroundImage(UIImage(named: "car"), for: .normal)
button.addTarget(self, action: #selector(MapVC.getDirections), for: .touchUpInside)
view.leftCalloutAccessoryView = button
} else {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
button.setBackgroundImage(UIImage(named: "other"), for: .normal)
button.addTarget(self, action: #selector(MapVC.other), for: .touchUpInside)
view.leftCalloutAccessoryView = button
}

return view
}
}

if let annotationView = map.dequeueReusableAnnotationView(withIdentifier: identifier) {
annotationView.annotation = annotation
return annotationView
} else {
let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier: identifier)
annotationView.isEnabled = true
annotationView.canShowCallout = true

let btn = UIButton(type: .detailDisclosure)
annotationView.rightCalloutAccessoryView = btn

if annotationView.pinTintColor == .red || annotationView.pinTintColor == .green {

let smallSquare = CGSize(width: 120, height: 120)
let button = UIButton(frame: CGRect(origin: CGPoint(x: 0,y :0), size: smallSquare))
button.setBackgroundImage(UIImage(named: "car"), for: .normal)
button.addTarget(self, action: #selector(MapVC.getDirections), for: .touchUpInside)
annotationView.leftCalloutAccessoryView = button
} else {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
button.setBackgroundImage(UIImage(named: "other"), for: .normal)
button.addTarget(self, action: #selector(MapVC.other), for: .touchUpInside)
annotationView.leftCalloutAccessoryView = button
}

return annotationView
}

}

Answer Source

The method func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? is a delegate method of MapViewDelegate, this method is executed every time that your mapView show an Annotation in a Region, and if is implemented you can show any subclass of annotationView as annotationView in the map, to show custom callout you need implement this method of MapViewDelegate

//example code
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView){
    let customCallout = CustomCallout(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width * 0.8, height: 50))
   customCallout.backgroundColor = UIColor.red //your color here
   view.addSubView(customCallout)
   //adjust any param you need here
}

Hope this helps you

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download