Swift different images for Annotation
Asked Answered
A

2

30

I managed to get a custom icon for a annotation pin in Swift, but now I am still stuck using 2 different images for different annotations. Right now a button adds a annotation to the map. There should be another button that also adds a annotation but with another icon.

Is there a way to use the reuseId for this?

class ViewController: UIViewController, MKMapViewDelegate {

@IBOutlet weak var Map: MKMapView!

@IBAction func btpressed(sender: AnyObject) {

    var lat:CLLocationDegrees = 40.748708
    var long:CLLocationDegrees = -73.985643
    var latDelta:CLLocationDegrees = 0.01
    var longDelta:CLLocationDegrees = 0.01

    var span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
    var location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, long)
    var region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)

    Map.setRegion(region, animated: true)


    var information = MKPointAnnotation()
    information.coordinate = location
    information.title = "Test Title!"
    information.subtitle = "Subtitle"

    Map.addAnnotation(information)
}

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
    if !(annotation is MKPointAnnotation) {
        return nil
    }

    let reuseId = "test"

    var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
    if anView == nil {
        anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        anView.image = UIImage(named:"1.png")
        anView.canShowCallout = true
    }
    else {
        anView.annotation = annotation
    }

    return anView
}
Attire answered 2/9, 2014 at 20:0 Comment(0)
S
83

In the viewForAnnotation delegate method, set the image based on which annotation the method is being called for.

Be sure to do this after the view is dequeued or created (and not only in the if anView == nil part). Otherwise, annotations that use a dequeued view will show the image of the annotation that used the view previously.

With the basic MKPointAnnotation, one crude way to tell annotations apart is by their title but that's not very flexible.

A better approach is to use a custom annotation class that implements the MKAnnotation protocol (an easy way to do that is to subclass MKPointAnnotation) and add whatever properties are needed to help implement the custom logic.

In the custom class, add a property, say imageName, which you can use to customize the image based on the annotation.

This example subclasses MKPointAnnotation:

class CustomPointAnnotation: MKPointAnnotation {
    var imageName: String!
}

Create annotations of type CustomPointAnnotation and set their imageName:

var info1 = CustomPointAnnotation()
info1.coordinate = CLLocationCoordinate2DMake(42, -84)
info1.title = "Info1"
info1.subtitle = "Subtitle"
info1.imageName = "1.png"

var info2 = CustomPointAnnotation()
info2.coordinate = CLLocationCoordinate2DMake(32, -95)
info2.title = "Info2"
info2.subtitle = "Subtitle"
info2.imageName = "2.png"

In viewForAnnotation, use the imageName property to set the view's image:

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
    if !(annotation is CustomPointAnnotation) {
        return nil
    }

    let reuseId = "test"

    var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
    if anView == nil {
        anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
        anView.canShowCallout = true
    }
    else {
        anView.annotation = annotation
    }

    //Set annotation-specific properties **AFTER**
    //the view is dequeued or created...

    let cpa = annotation as CustomPointAnnotation
    anView.image = UIImage(named:cpa.imageName)

    return anView
}
Susannsusanna answered 3/9, 2014 at 2:17 Comment(8)
Simple and straightforward +1Halfwit
Just a note that you need to implement the protocol 'MKMapViewDelegate' and configure your controller to be your delegate (either in the storyboard or manually in the code) for the func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! method to work. This tripped me up for a bit.Hair
the best answer i found for this question. +1 for the order and the simplicity of the answerFrantic
@Anna my pin points are not displaying on the map. only callout is there. whats wrongDisencumber
Hi @Anna, My all points are not covered in my UImapview, it is going out of bounds... What should be the case?Retake
@Anna how would I do this to display a different callout view for each of the 3 annotation types I have? ThanksEnslave
fatal error: unexpectedly found nil while unwrapping an Optional value . I'm getting this error at let cpa = annotation as! CustomPointAnnotation Bout
i am use this but it is also show default pin image.Beefwood
F
13

iOS Swift Code With Help of Anna and Fabian Boulegue:

import UIKit
import MapKit

class ViewController: UIViewController, MKMapViewDelegate {

    @IBOutlet weak var mapView: MKMapView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.mapView.delegate = self

        var info1 = CustomPointAnnotation()
        info1.coordinate = CLLocationCoordinate2DMake(26.889281, 75.836042)
        info1.title = "Info1"
        info1.subtitle = "Subtitle"
        info1.imageName = "flag.png"

        var info2 = CustomPointAnnotation()
        info2.coordinate = CLLocationCoordinate2DMake(26.862280, 75.815098)
        info2.title = "Info2"
        info2.subtitle = "Subtitle"
        info2.imageName = "flag.png"

        mapView.addAnnotation(info1)
        mapView.addAnnotation(info2)
    }

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

        println("delegate called")

        if !(annotation is CustomPointAnnotation) {
            return nil
        }

        let reuseId = "test"

        var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
        if anView == nil {
            anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
            anView.canShowCallout = true
        }
        else {
            anView.annotation = annotation
        }

        //Set annotation-specific properties **AFTER**
        //the view is dequeued or created...

        let cpa = annotation as CustomPointAnnotation
        anView.image = UIImage(named:cpa.imageName)

        return anView
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

class CustomPointAnnotation: MKPointAnnotation {
    var imageName: String!
}
Frightened answered 13/3, 2015 at 6:42 Comment(3)
for Swift 3 I had to change to use: func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {Heads
Need to downcast the annotation to CustomPointAnnotation. Change it to let pickupCustomAnno = annotation as! CustomPointAnnotationPantaloons
would that be bad to leave the reuseId as "test" ? what would that bring ?Heilner

© 2022 - 2024 — McMap. All rights reserved.