1

I've been working on an app that has an MKMapView and I want to customize the pins with different images. I've already did that but with one image only, now I need to make a pin show an image and the other pin show another image. How can I do this? If helps, here's my code:

-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation{

MKAnnotationView *pinView = nil;
if(annotation != _mapView.userLocation)
{
    static NSString *defaultPinID;
    pinView = (MKAnnotationView *)[_mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
    if ( pinView == nil )
        pinView = [[MKAnnotationView alloc]
                   initWithAnnotation:annotation reuseIdentifier:defaultPinID];


    pinView.canShowCallout = YES;
    pinView.image = [UIImage imageNamed:@"image1.jpg"];
}
else {
    [_mapView.userLocation setTitle:@"Your Location"];
}
return pinView;   }

I need the second and the third to show the same image but the first a different one It follows like this:

- (void)viewWillAppear:(BOOL)animated {CLLocationCoordinate2D First; First.latitude = -12.098970; First.longitude = -77.034531; MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init]; annotationPoint.coordinate = First; annotationPoint.title = @"First"; annotationPoint.subtitle = @"Subtitle1"; [_mapView addAnnotation:annotationPoint];

CLLocationCoordinate2D Second; Second.latitude = -12.098299; Second.longitude = -77.068364; MKPointAnnotation *annotationPoint2 = [[MKPointAnnotation alloc] init]; annotationPoint2.coordinate = Second; annotationPoint2.title = @"Second"; annotationPoint2.subtitle = @"Subtitle2"; [_mapView addAnnotation:annotationPoint2];

CLLocationCoordinate2D Third; Third.latitude = -12.125888; Third.longitude = -77.023346; MKPointAnnotation *annotationPoint3 = [[MKPointAnnotation alloc] init]; annotationPoint3.coordinate = Third; annotationPoint3.title = @"Third"; annotationPoint3.subtitle = @"Subtitle3"; [_mapView addAnnotation:annotationPoint3];}
rafiki92
  • 21
  • 2
  • 4
  • Welcome to Stack Overflow. Your question might have already been answered here http://stackoverflow.com/questions/15950698/custom-pin-on-mkmapview-in-ios – sangony Feb 17 '14 at 02:02
  • Hi @sangony, thanks for the answer. I've already take a look at that and it only explains what I've already done. If I wasn't clear, I want the first pin to show an image and the second and third pins to show another image, not the same as the first pin. – rafiki92 Feb 17 '14 at 02:06
  • @rafiki92: See [this answer](http://stackoverflow.com/questions/20449716/custom-annotation-apple-mapkit) for an example of the custom class and property approach. –  Feb 17 '14 at 19:52
  • For an example of the simple check-the-title approach, see [this answer](http://stackoverflow.com/a/10799746/467105). Only look at how it's setting the `image` property based on the annotation's `title` (the way that answer is checking for "current location" is not recommended). –  Feb 17 '14 at 19:59

1 Answers1

5

Make sure you have MapKit.framework and CoreLocation.framework in your project.

My custom pin images are 39 high by 32 wide. Have not tried other sizes but feel free to experiment. My 2 pin images are called pin1.png and pin2.png

Make sure you have your images named correctly to match what is in your code.

In my example I am not using current location but rather a static custom location (thought The Bahamas would be nice for this example). In your project you would of course you the Location Manager to get a user's current location.

I have tested my example and have successfully dropped 2 pins on the map with each pin having its own custom image.

It's not the cleanest code but I only had limited time to write it.

Here is the code for ViewController.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>

@interface ViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate>

@end

Here is the code for ViewController.h

#import "ViewController.h"
#import "MyAnnotation.h"
#import <MapKit/MapKit.h>

@interface ViewController ()

@property (strong, nonatomic) IBOutlet MKMapView *myMapView;

@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];

    // setup the map view, delegate and current location

    [self.myMapView setDelegate:self];

    self.myMapView.mapType = MKMapTypeStandard;

    CLLocationCoordinate2D myLocation = CLLocationCoordinate2DMake(25.085130,-77.331428);
    [self.myMapView setCenterCoordinate:myLocation];

    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(myLocation, 2000, 2000);
    region.center = self.myMapView.centerCoordinate;
    self.myMapView.showsUserLocation = YES;
    [self.myMapView setRegion:region animated:YES];

    [self dropPins];
}

-(void)dropPins {
    NSMutableArray *annotationArray = [[NSMutableArray alloc] init];

    CLLocationCoordinate2D location1 = CLLocationCoordinate2DMake(25.085130, -77.331428);
    MyAnnotation *annotation1 = [[MyAnnotation alloc] initWithCoordinates:location1 image:@"pin1.png"];
    [annotationArray addObject:annotation1];
    [self.myMapView addAnnotations:annotationArray];

    [annotationArray removeAllObjects];
    CLLocationCoordinate2D location2 = CLLocationCoordinate2DMake(25.085130, -77.336428);
    MyAnnotation *annotation2 = [[MyAnnotation alloc] initWithCoordinates:location2 image:@"pin2.png"];
    [annotationArray addObject:annotation2];
    [self.myMapView addAnnotations:annotationArray];
}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    static NSString *identifier = @"MyLocation";
    if ([annotation isKindOfClass:[MyAnnotation class]])
    {
        MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.myMapView dequeueReusableAnnotationViewWithIdentifier:identifier];

        if (annotationView == nil)
        {
            annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        } else
        {
            annotationView.annotation = annotation;
        }

        annotationView.enabled = YES;
        annotationView.canShowCallout = NO;

        if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:@"pin1.png"])
            annotationView.image = [UIImage imageNamed:@"pin1.png"];

        if([[(MyAnnotation *)annotationView.annotation image] isEqualToString:@"pin2.png"])
            annotationView.image = [UIImage imageNamed:@"pin2.png"];

        return annotationView;
    }
    return nil;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Here is the code for MyAnnotation.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MyAnnotation : NSObject <MKAnnotation>

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy, readonly) NSString *image;


-(id)initWithCoordinates:(CLLocationCoordinate2D) paramCoordinates
                   image:(NSString *) paramImage;

@end

Here is the code for MyAnnotation.m

#import "MyAnnotation.h"

@implementation MyAnnotation

-(id)initWithCoordinates:(CLLocationCoordinate2D)paramCoordinates
                   image:(NSString *)paramImage
{
    self = [super init];
    if(self != nil)
    {
        _coordinate = paramCoordinates;
        _image = paramImage;
    }
    return (self);
}

@end
shellco
  • 536
  • 1
  • 6
  • 25
sangony
  • 11,636
  • 4
  • 39
  • 55
  • Could you please write an example with my code above? I'm pretty new at this and what I'm doing is not working in any way... Thanks! – rafiki92 Feb 17 '14 at 03:50
  • There is no guarantee that viewForAnnotation will get called immediately after doing addAnnotation and it's also possible for viewForAnnotation to get called _multiple_ times for the same annotation after it's already been added (eg. if you zoom/pan the map and the annotation comes into view again). So this method of using a single VC-level instance variable is unreliable. One crude solution is to check the annotation's title in viewForAnnotation. Better approach is to use a custom annotation class with an image name/id property in it. –  Feb 17 '14 at 14:19
  • You are absolutely right @Anna but I don't know his full code. Hopefully he will understand what is being done and work it properly into his code structure. – sangony Feb 17 '14 at 14:44
  • Thank you sangony for the code, but it's not working properly. When I start the application, it shows only the second image but no the first one. @Anna, how may I apply what you are saying in my code? – rafiki92 Feb 17 '14 at 19:06
  • And you were right. My previous answer did not work as I stated it. The key was to include a string property in the annotation class which contains the image name for the pin to be used. – sangony Feb 18 '14 at 02:18