62
votes

I want to display an image in my MKMapView instead of little rock pin.

Can someone please put some helpful code here, or tell the way how to do it?

-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:
    (id <MKAnnotation>)annotation {
    MKPinAnnotationView *pinView = nil; 
    if(annotation != mapView.userLocation) 
    {
        static NSString *defaultPinID = @"com.invasivecode.pin";
        pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
        if ( pinView == nil ) pinView = [[MKPinAnnotationView alloc]
                                          initWithAnnotation:annotation reuseIdentifier:defaultPinID];

        pinView.pinColor = MKPinAnnotationColorGreen; 
        pinView.canShowCallout = YES;
        pinView.animatesDrop = YES;
        pinView.image = [UIImage imageNamed:@"pinks.jpg"]; //as suggested by Squatch
    } 
    else {
        [mapView.userLocation setTitle:@"I am here"];
    }
    return pinView;
}

I am expecting my image pinks.jpg to be on the map, pinning the location instead of default pin view (rock pin shaped). But still I am getting the default image of the pin.

3
Sounds like you want a custom annotation. Check this tutorial out. Googling for a custom annotation tutorial will also get you going if that one doesn't suit you.Squatch
I guess Annotation is just the note that is put to tell information about the pinned location. But I want to customize the pin, that change its image to a company logo.turtle
I have also tried you tutorial way, seems it's not worked out for me. Tutorial is setting image property of MKAnnotationView object to some UIImage. This I have tested, doesn't change the pinView to my assigned image.turtle
@turtle, can you post the code you tried, what happens and what you expected?user467105
@AnnaKarenina : I have edited my question, you may look at the code. Thanks..turtle

3 Answers

118
votes

When you want to use your own image for an annotation view, you should create an MKAnnotationView instead of an MKPinAnnotationView.

MKPinAnnotationView is a subclass of MKAnnotationView so it has an image property but it generally overrides that and draws a pin image (that's what it's for).

So change the code to:

-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation 
{
    MKAnnotationView *pinView = nil; 
    if(annotation != mapView.userLocation) 
    {
        static NSString *defaultPinID = @"com.invasivecode.pin";
        pinView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
        if ( pinView == nil ) 
            pinView = [[MKAnnotationView alloc]
                                         initWithAnnotation:annotation reuseIdentifier:defaultPinID];

        //pinView.pinColor = MKPinAnnotationColorGreen; 
        pinView.canShowCallout = YES;
        //pinView.animatesDrop = YES;
        pinView.image = [UIImage imageNamed:@"pinks.jpg"];    //as suggested by Squatch
    } 
    else {
        [mapView.userLocation setTitle:@"I am here"];
    }
    return pinView;
}


Notice that animatesDrop is also commented out since that property only exists in MKPinAnnotationView.

If you still want your image annotations to drop, you'll have to do the animation yourself. You can search Stack Overflow for "animatesdrop mkannotationview" and you'll find several answers. Here are the first two:

19
votes

Here's an answer on Swift 3. It dequeues annotation view if possible or creates a new one if not:

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
    }

    // Better to make this class property
    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
}
0
votes

I agree with with answer of the Anna and i like to show how will look that in swift3.This answer it's with many other options.Like a resize the image, get a list of images from array and ect.

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        if let annotation = annotation as? PetrolStation {
            let identifier = "pinAnnotation"
            var view: MKAnnotationView
            if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
                as? MKPinAnnotationView { // 2
                dequeuedView.annotation = annotation
                view = dequeuedView
            } else {
                // 3
                view = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
                view.canShowCallout = true

                //here We put a coordinates where we like to show bubble with text information up on the pin image
                view.calloutOffset = CGPoint(x: -7, y: 7)


                //Here this is a array of images
                let pinImage = PetrolItem[activePlace].imgPetrol?[activePlace]

                //Here we set the resize of the image
                let size = CGSize(width: 30, height: 30)
                UIGraphicsBeginImageContext(size)
                pinImage?.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
                let resizeImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                view.image = resizeImage

                //Here we like to put into bubble window a singe for detail Informations
                view.rightCalloutAccessoryView = UIButton(type: .detailDisclosure) as UIView
               //Here we make change of standard pin image with our image
                view.image = resizeImage
            }

            return view
        }
        return nil
    }