Search code examples
swiftannotationsmkmapview

Swift 3.0 Pin Color Annotation Not Changing in MapView


I am interested in changing the pin color of an annotation based on a case scenario. In one function, I have an array sent that determines what color the pin annotation is. Thus far, I have set a subclass called ColorPointAnnotation which will determine the pinColor. Then, in the switch statement, I set the ColorPointAnnotation for the annotation. And in the viewForAnnotation, I place the new annotation with the color. From my understanding of annotations from documentation, that is all that is required, however, the pin color is not changing on the mapView. I am not sure what could be the issue.

class ColorPointAnnotation: MKPointAnnotation {
    var pinColor: UIColor

    init(pinColor: UIColor) {
        self.pinColor = pinColor
        super.init()
    }
}

//here is the function that pulls the array from another view controller
func add(newLocation location_one:[String:Any]) {

    let momentaryLat = (location_one["latitude"] as! NSString).doubleValue
    let momentaryLong = (location_one["longitude"] as! NSString).doubleValue

    var annotation = MKPointAnnotation()

    switch String(describing: location_one["eventType"]!) {
        case "No":
            print("Attending Event")
            annotation = ColorPointAnnotation(pinColor: UIColor.red)
        case "Yes":
            print("Hosting Event")
            annotation = ColorPointAnnotation(pinColor: UIColor.green)
        default:
            print("The pin color is purple")
            annotation = ColorPointAnnotation(pinColor: UIColor.purple)
    }

    annotation.title = location_one["title"] as? String
    annotation.coordinate = CLLocationCoordinate2D(latitude: momentaryLat as CLLocationDegrees, longitude: momentaryLong as CLLocationDegrees)


    DispatchQueue.main.async {
        self.map.addAnnotation(annotation)
    }

    self.map.centerCoordinate = annotation.coordinate

}

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

    //        if (annotation is MKUserLocation) {
    //            return nil
    //        }

    let identifier = "pinAnnotation"
    var annotationView = map.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView


    if annotationView == nil {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        annotationView?.canShowCallout = true
        let colorPointAnnotation = annotation as! ColorPointAnnotation
        annotationView?.pinTintColor = colorPointAnnotation.pinColor


    }
    //      else {
    //            annotationView?.annotation = annotation
    //
    //        }
    //        map.showAnnotations(map.annotations, animated: true)
    return annotationView
}

Solution

  • I think your main problem is that you have either have not set map.delegate = self, or your view controller is not inheriting from MKMapViewDelegate.

    I have tidied up your code as well, and this code below is functioning properly.

    I have also modified your ColorPointAnnotation class to work better.

    class ColorPointAnnotation: MKPointAnnotation {
    
        var color: UIColor!
    }
    

    View Controller

    import UIKit
    import MapKit
    
    class ViewController: UIViewController, MKMapViewDelegate {
    
        @IBOutlet weak var map: MKMapView!
    
        var locations = Array<Dictionary<String,Any>>()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Add some test pins
    
            var attending = Dictionary<String,Any>()
    
            attending["latitude"] = 40.83
    
            attending["longitude"] = -73.93
    
            attending["eventType"] = "No"
    
            attending["title"] = "Testing Attending"
    
            self.locations.append(attending)
    
    
            var hosting = Dictionary<String,Any>()
    
            hosting["latitude"] = 37.77
    
            hosting["longitude"] = -122.45
    
            hosting["eventType"] = "Yes"
    
            hosting["title"] = "Testing Hosting"
    
            self.locations.append(hosting)
    
    
            var location = Dictionary<String,Any>()
    
            location["latitude"] = 33.73
    
            location["longitude"] = -84.39
    
            location["title"] = "Testing Default"
    
            self.locations.append(location)
    
    
            // Add test pins to map
    
            for item in locations {
    
                add(new: item)
            }
        }
    
        func add(new location: Dictionary<String,Any>) {
    
            guard
    
                let latitude = location["latitude"] as? Double,
    
                let longitude = location["longitude"] as? Double,
    
                let title = location["title"] as? String
    
            else {
    
                print("Incomplete Data")
    
                return
            }
    
            let annotation = ColorPointAnnotation()
    
            if let eventType = location["eventType"] as? String {
    
                switch eventType {
    
                case "No":
    
                    print("Attending Event")
    
                    annotation.color = .red
    
                    break
    
                case "Yes":
    
                    print("Hosting Event")
    
                    annotation.color = .green
    
                    break
    
                default :
    
                    // I don't need to set this to purple because if 
                    // annotation.color is nil purple will be the default
    
                    break
                }
            }
    
            annotation.title = title
    
            annotation.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    
            self.map.addAnnotation(annotation)
        }
    
        func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    
            if let pin = annotation as? ColorPointAnnotation {
    
                let identifier = "pinAnnotation"
    
                if let view = map.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView {
    
                    view.pinTintColor = pin.color ?? .purple
    
                    return view
    
                } else {
    
                    let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
    
                    view.canShowCallout = true
    
                    view.pinTintColor = pin.color ?? .purple
    
                    return view
                }
            }
    
            return nil
        }
    }
    

    This is how the code above looks.