Search code examples
iosswiftmapkitmkpointannotation

Set individual glyphtext for MKAnnotations


I want to create MKPointAnnotaion's with the identifier number in the annotation overlay instead of the pin. So a 1 for the first annotation, a 2 for the second annotation, etc.

First, I added an MKPointAnnotation to the mapView based on a UILongPressGestureRecognizer.

With the mapView(_:viewFor:) I want to style those Annotations. This works to a certain extent but brings us to my problem:

I created a class CustomAnnotation to add an identifier to my MKPointAnnotaion:

class CustomAnnotation: MKPointAnnotation {
    var identifier: Int!
}

And I set the identifier when registering UILongPressGesture:

let annotation = CustomAnnotation()
annotation.identifier = mapView.annotations.count

Then I use mapView(_:viewFor:) to change the appearance of my MKPointAnnotaion's. But I do not know how to set annotationView.glyphText so that it uses the identifier defined before for every created annotation individually.

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

        let annotationView = MKMarkerAnnotationView()
        annotationView.glyphTintColor = .white
        annotationView.glyphText = "44"
            
        return annotationView
    }
}

Solution

  • Thank you @Gerd Castan for your reference to the very extensive tutorial at kodeco

    In the following I give a brief overview how I solved my problem - it might help someone in the future.

    First of all I changed the type of my CustomAnnotation class from a MKPointAnnotationto an MKAnnotation. Now it is actually applicable to every Map Annotation use case.

    class CustomAnnotation: NSObject, MKAnnotation {
        @objc dynamic var coordinate: CLLocationCoordinate2D
        var title:String?
        var subtitle: String?
        var identifier: Int?
        
        init(coordinate:CLLocationCoordinate2D,
             title:String?, subtitle:String?, identifier:Int?) {
            self.coordinate = coordinate
            self.title = title
            self.subtitle = subtitle
            self.identifier = identifier
       }
    }
    

    Then I created a class for the view representation of the CustomAnnotation called CustomAnnotationView. In this case the type is an MKMarkerAnnotationView but you can also use MKAnnotationView if you do not want the representation of the Annotations as markers.

    class CustomAnnotationView: MKMarkerAnnotationView {
        override var annotation: MKAnnotation?{
            willSet{
                
                guard let marker = newValue as? CustomAnnotation else { return }
    
                if let number = marker.identifier {
                   let alphabeticRepresentation = UnicodeScalar(number+1+64)!
                   glyphText = String(alphabeticRepresentation)
                }
                
            }
        }
        
    }
    
    

    One annotation to the code cell above:

    1. If you do not want an alphabetic representation in your marker, then just delete the following line of code in the example above let alphabeticRepresentation = UnicodeScalar(number+1+64)!

    In my UILongPressureGesture handler I set the identifier, so only the number of CustomAnnotaion's are counted.

    let identifier = mapView.annotations.filter{ $0 is CustomAnnotation }.count
    

    In viewDidload() of the MapViewController I registered the CustomAnnotationView

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

    That's it.