How to add custom images to annotations in Mapview Swift ios?

17.2k views Asked by At
 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)

    mapView.setRegion(region, animated: true)


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



    mapView.addAnnotation(information)
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {


    if !(annotation is MKPointAnnotation) {
        return nil
    }

    let reuseId = "test"

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

    return anView
}

I need to load custom image for the annotation in Mapview. I have an image named "Annotation" and I am trying to call it in viewfor annotation method. How can I achieve this?

5

There are 5 answers

3
Hrishikesh On

Here is the answer:

Swift 4:

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 {
        let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
        av.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
        annotationView = av
    }

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

    return annotationView
}

Swift 3:

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
}

Swift 2.2:

func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    // Don't want to show a custom image if the annotation is the user's location.
    guard !annotation.isKindOfClass(MKUserLocation) else {
        return nil
    }

    let annotationIdentifier = "AnnotationIdentifier"

    var annotationView: MKAnnotationView?
    if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotationIdentifier) {
        annotationView = dequeuedAnnotationView
        annotationView?.annotation = annotation
    }
    else {
        let av = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
        av.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
        annotationView = av
    }

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

    return annotationView
}
3
Ankit Saini On

The best way to achieve this is using custom class to store annotations.

import UIKit
import MapKit
import CoreLocation

class Annotation: NSObject, MKAnnotation {

var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D()
var title: String?
var subtitle: String?

var strTitle = ""
var strImgUrl = ""
var strDescr = ""


init(coordinates location: CLLocationCoordinate2D, title1: String, description: String, imgURL: String) {
    super.init()

    coordinate = location
    title = title1
    subtitle = description
    strTitle = title1
    strImgUrl = imgURL
    strDescr = description
}
}

Now use this class to store annotation and populate your pins.

//  MapViewController.swift
let myAnnotation1: Annotation = Annotation.init(coordinates: CLLocationCoordinate2D.init(latitude: 30.733051, longitude: 76.763042), title1: "The Mayflower Renaissance Hotel", description: "The Histroic hotel has been the site of saveral dramatic locations.", imgURL: "custom.jpg")
    self.uvMApView.addAnnotation(myAnnotation1)

  func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
   if (annotation is MKUserLocation) {
        return nil
    }
    // try to dequeue an existing pin view first
    let AnnotationIdentifier = "AnnotationIdentifier"

    let myAnnotation1 = (annotation as! Annotation)

    let pinView = MKAnnotationView(annotation: annotation, reuseIdentifier: AnnotationIdentifier)
    pinView.canShowCallout = true
    pinView.image = UIImage(named: myAnnotation1. strImgUrl)!
    return pinView

   }
0
Gurjinder Singh On

Swift 4.0

var coordinates: [[Double]]!
var addresses:[String]!

In viewDidload() add following code to add annotations to MapvView.

    coordinates = [[28.4344,72.5401],[28.85196,72.3944],[28.15376,72.1953]]// Latitude,Longitude
    addresses = ["Address1","Address2","Address3"]
    self.mapView.delegate = self // set MapView delegate to self
    for i in 0...2 {
        let coordinate = coordinates[i]
        let point = CustomAnnotation(coordinate: CLLocationCoordinate2D(latitude: coordinate[0] , longitude: coordinate[1] )) // CustomAnnotation is class and pass the required param
        point.address = addresses[i] // passing only address to pin, you can add multiple properties according to need
        self.mapView.addAnnotation(point)
    }
    let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 28.856614, longitude: 72.3522219), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
    self.mapView.setRegion(region, animated: true)

Add new class having name CustomAnnotation inherited from MKAnnotation for our custom annotation

import MapKit
class CustomAnnotation: NSObject, MKAnnotation {
    var coordinate: CLLocationCoordinate2D
    var address: String!
    init(coordinate: CLLocationCoordinate2D) {
        self.coordinate = coordinate
    }
}

Add one more class having name AnnotationView inherited from MKAnnotationView. I am showing custom callout so it it is required to to override the overridefuncpoint() method to receive touch in custom callout view.

import MapKit
class AnnotationView: MKAnnotationView
{
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let hitView = super.hitTest(point, with: event)
        if (hitView != nil)
        {
            self.superview?.bringSubview(toFront: self)
        }
        return hitView
    }
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let rect = self.bounds;
        var isInside: Bool = rect.contains(point);
        if(!isInside)
        {
            for view in self.subviews
            {
                isInside = view.frame.contains(point);
                if isInside
                {
                    break;
                }
            }
        }
        return isInside;
    }
}

Now implement viewForannotation MapView delegate as follow

    extension YourViewC: MKMapViewDelegate {

        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            if annotation is MKUserLocation
            {
                return nil
            }
            var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: "CustomPin")
            if annotationView == nil{
                annotationView = AnnotationView(annotation: annotation, reuseIdentifier: "CustomPin")
                annotationView?.canShowCallout = false
            }else{
                annotationView?.annotation = annotation
            }
            annotationView?.image = UIImage(named: "bluecircle") // Pass name of your custom image
            return annotationView
        }
     func mapView(_ mapView: MKMapView,
                 didSelect view: MKAnnotationView){ 
        let annotation = view.annotation as? CustomAnnotation
       print(annotation?.address) // get info you passed on pin

      // write code here to add custom view on tapped annotion
}
0
SphynxTech On

You can also do like this:

    let reuseId = "pin"
    var your_pin = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
    let your_image = UIImage (named: "your_image")

    pinView?.image = your_image
    pinView?.canShowCallout = true

I think it is the more easily answer.

0
Arshad Shaik On

After spending lot of time, i came up with a simple code.
1. Don't use .pdf images, use only .png images with three different sizes such as 1x, 2x, 3x. Below is my sample code.

@IBOutlet var mapView: MKMapView!
let locationManager = CLLocationManager()

override func viewDidLoad() {
    super.viewDidLoad()

    mapViewSetup()
}

func mapViewSetup(){
        self.locationManager.requestAlwaysAuthorization()
        // For use in foreground
        self.locationManager.requestWhenInUseAuthorization()

        if CLLocationManager.locationServicesEnabled() {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.startUpdatingLocation()
        }

        mapView.delegate = self
        mapView.mapType = .standard
        mapView.isZoomEnabled = true
        mapView.isScrollEnabled = true
        mapView.showsUserLocation = false

        if let coor = mapView.userLocation.location?.coordinate{
            mapView.setCenter(coor, animated: true)
        }
    }

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let locValue:CLLocationCoordinate2D = manager.location!.coordinate

        mapView.mapType = MKMapType.standard

        let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
        let region = MKCoordinateRegion(center: locValue, span: span)
        mapView.setRegion(region, animated: true)

        let annotation = MKPointAnnotation()
        annotation.coordinate = locValue
        annotation.title = "Arshad"
        annotation.subtitle = "BrightSword Technologies Pvt Ltd"
        mapView.addAnnotation(annotation)

        self.locationManager.stopUpdatingLocation()

        //centerMap(locValue)
    }

private func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print(error.localizedDescription)
    }

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        if annotation is MKUserLocation {
            return nil
        }

        let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "customannotation")
        annotationView.image = UIImage(named: "icon_location_pin")
        annotationView.canShowCallout = true

        return annotationView
    }

Hope it will help someone.