Search code examples
iosswiftannotationsmapkit

Annotation Pin color and Type


My app has a method to add annotation to a map

 var annotationArray = [MyAnnotation]()
 var allAnnotations: [(objLat: CLLocationDegrees, objLong: CLLocationDegrees, objName: String, objDesc: String, objId: String)] = []

  func addAnnotationsToMap() {
    annotationArray = []
        for oneObject in self.allAnnotations {
            let oneAnnotation = MyAnnotation()
            let oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
            oneAnnotation.coordinate = oneObjLoc
            oneAnnotation.title = oneObject.objName
            oneAnnotation.subtitle = oneObject.objDesc
            oneAnnotation.mapId = oneObject.objId

            self.annotationArray.append(oneAnnotation)
        }
        self.map.addAnnotations(self.annotationArray)
        self.allAnnotations = []
        self.annotationArray = []
   }

MyAnnotation is

import UIKit
import MapKit

class MyAnnotation: MKPointAnnotation {
    var mapId = String()
    var phone1 = String()
    var phone2 = String()
    var specialty1 = String()
    var specialty2 = String()
}

Depending on the specialty1 type I want to have a different Pin Color (and type) and I'm trying to use the method below. The one thing that stops showing is the Pin title tough (that is something I want to keep)

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    let annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil)

    annotationView.pinTintColor = UIColor.red

    return annotationView
}

My idea is to use the Pin below in different colors

Pin

If I remove the viewFor Annotation I get a Pin with a title.

There are several posts showing how to add a different color to an annotation but all of them are using addAnnotation instead of addAnnotations.

What am I missing? Is there a way to do what I need?

Thanks


Solution

  • The MKPinAnnotationView doesn’t show the name under the pin. It shows it only when you tap on it and when you show callouts.

    If you want this style of round annotation view with the name underneath it, should use MKMarkerAnnotationView. And to change its color, you set markerTintColor.


    By the way, I would not advise instantiating your annotation views directly like that.

    I’d suggest registering a reuse id in viewDidLoad:

    mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
    

    And then, in viewFor, you can dequeue a reusable annotation view like so:

    let view = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier, for: annotation) as! MKMarkerAnnotationView
    view.markerTintColor = ...
    

    This is more efficient when you can start reusing annotation views..


    Nowadays, I’d take it even a step further, remove viewFor entirely, and put the configuration of the annotation view in the annotation view class, where it belongs. (It’s why we use MKMapViewDefaultAnnotationViewReuseIdentifier.)

    For example, I’d subclass MKMarkerAnnotationView:

    class MyAnnotationView: MKMarkerAnnotationView {
        override var annotation: MKAnnotation? { didSet { update(for: annotation) } }
    
        override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
            super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
            update(for: annotation)
        }
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
    }
    
    
    private extension MyAnnotationView {
        func update(for annotation: MKAnnotation?) {
            guard let annotation = annotation as? MyAnnotation else { return }
    
            markerTintColor = ...
        }
    }
    

    And then in viewDidLoad you register this annotation view:

    mapView.register(MyAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
    

    But in this pattern, you don’t implement viewFor at all. You only need to do that if you have multiple custom annotation reuse identifiers.