Custom pin image in annotationView in iOS
Asked Answered
K

3

19

I'm trying to change from Swift 1.2 to Swift 2.0 and I'm at the end of the changes. Currently I'm making changes in the MapViewController, and there isn't any error or warning, but the custom image for my pin (annotationView) it's not assigned to the pin and it's showing the default one (red dot).

Here is my code, I hope you can help me with some tip because I think everything is fine but it's still not working:

func parseJsonData(data: NSData) -> [Farmacia] {

    let farmacias = [Farmacia]()

    do
    {
        let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary

        // Parse JSON data
        let jsonProductos = jsonResult?["farmacias"] as! [AnyObject]

        for jsonProducto in jsonProductos {

            let farmacia = Farmacia()
            farmacia.id = jsonProducto["id"] as! String
            farmacia.nombre = jsonProducto["nombre"] as! String
            farmacia.location = jsonProducto["location"] as! String

            let geoCoder = CLGeocoder()
            geoCoder.geocodeAddressString(farmacia.location, completionHandler: { placemarks, error in

                if error != nil {
                    print(error)
                    return
                }

                if placemarks != nil && placemarks!.count > 0 {

                    let placemark = placemarks?[0]

                    // Add Annotation
                    let annotation = MKPointAnnotation()
                    annotation.title = farmacia.nombre
                    annotation.subtitle = farmacia.id
                    annotation.coordinate = placemark!.location!.coordinate

                    self.mapView.addAnnotation(annotation)
                }

            })
        }
    }
    catch let parseError {
        print(parseError)
    }

    return farmacias
}

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

    let identifier = "MyPin"

    if annotation.isKindOfClass(MKUserLocation) {
        return nil
    }

    // Reuse the annotation if possible
    var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)

    if annotationView == nil
    {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        annotationView!.canShowCallout = true
    }

    annotationView!.image = UIImage(named: "custom_pin.png")

    let detailButton: UIButton = UIButton(type: UIButtonType.DetailDisclosure)
    annotationView!.rightCalloutAccessoryView = detailButton

    print(annotationView!.image)

    return annotationView
}

Thanks in advance,

Regards.

Katricekatrina answered 29/9, 2015 at 9:3 Comment(0)
E
49

The accepted answer doesn't work, as it has annotationView uninitialized in else block.

Here's a better solution. It dequeues annotation view if possible or creates a new one if not:

// https://mcmap.net/q/628382/-custom-pin-image-in-annotationview-in-ios
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    // Don't want to show a custom image if the annotation is the user's location.
    guard !(annotation is MKUserLocation) else {
        return nil
    }

    // Better to make this class property
    let annotationIdentifier = "AnnotationIdentifier"

    var annotationView: MKAnnotationView?
    if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
        annotationView = dequeuedAnnotationView
        annotationView?.annotation = annotation
    }
    else {
        annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
        annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
    }

    if let annotationView = annotationView {
        // Configure your annotation view here
        annotationView.canShowCallout = true
        annotationView.image = UIImage(named: "yourImage")
    }

    return annotationView
}
Enteron answered 2/7, 2016 at 10:22 Comment(3)
This helped me much more than the accepted answer, thanks a lot @Andrey GordeevNoddy
Wow!!! This seriously saved me!!! I was having some serious perf issues but seeing this example on how to properly use the identifier really helped. I thought I was using it correctly to begin with too. This should be the accepted answer!Maurizio
You can actually make this simpler if you dequeue when declaring the "annotationView". See my answer.Phenolphthalein
K
16

Here is the answer:

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

    let identifier = "MyPin"

    if annotation.isKindOfClass(MKUserLocation) {
        return nil
    }

    let detailButton: UIButton = UIButton(type: UIButtonType.DetailDisclosure)

    if let annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier) {
        annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "pin")
        annotationView.canShowCallout = true
        annotationView.image = UIImage(named: "custom_pin.png")
        annotationView.rightCalloutAccessoryView = detailButton
    }
    else {
        annotationView.annotation = annotation
    }

    return annotationView
}

Regards

Katricekatrina answered 29/9, 2015 at 10:14 Comment(3)
Thanks for sharing your solutions . It helped me tooLepto
Down voted. 1) "annotationView" instance is created in if-let scope and don't exist in else-scope. 2) If you succesfully can dequeue an annotationview, then you should use that and not creatie a new instance. The new instance should be created in the else-scope, where a reusable can't be dequeued.Phenolphthalein
I thought one needed MKPinAnnotation as a child of MKAnnotationMonorail
P
0

SWIFT 3,4

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

    if annotation.isKind(of: MKUserLocation.self) {
        return nil
    }

    let annotationIdentifier = "AnnotationIdentifier"

    var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier)
    if (pinView == nil) {
        pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
    }

    pinView?.canShowCallout = false

    return pinView
}
Phenolphthalein answered 12/12, 2017 at 8:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.