MKMapView with custom MKAnnotation

3 Solutions Collect From Internet About “MKMapView with custom MKAnnotation”

If you totally want to customize the callout View of the annotation..
See this link..

First, let’s define custom as meaning not simply title and subtitle. We want to change the size of the MKAnnotation and include some custom graphics.

There are two parts to an annotation you might want to customize:

  • MKAnnotation
  • MKAnnotationView

For the most basic MKAnnotation you would simply adopt the protocol and return nil for title and subtitle, but you could also carry a lot more information in your annotation for an extended callout upon tapping an accessory indicator. You can add all of the annotations to the MKMapView using addAnnotation: in viewDidLoad for example.

MKAnnotation Header

@interface CPAnnotation : NSObject <MKAnnotation> {
    CLLocationCoordinate2D _coordinate;
    NSString *_title;
    NSString *_subtitle;

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

- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate;

MKAnnotation Implementation

@implementation CPAnnotation
@synthesize coordinate = _coordinate;
@synthesize title = _title;
@synthesize subtitle = _subtitle;

- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate {
    self = [super init];

    if (self != nil) {
        self.coordinate = coordinate;

    return self;

- (NSString *)title {
    return _title;

- (NSString *)subtitle {
    return _subtitle;

The next step is to customize the callout from the pin dropped. To do this you need to customize MKAnnotationView. According to Apple you shouldn’t make a huge callout by default. They recommend a standard size callout that has a button to open a bigger one. They use the lowercase i in a blue circle icon. Those icons can be set via the view’s leftCalloutAccessoryView and rightCalloutAccessoryView property. If you already adopted the MKMapViewDelegate protocol and set yourself as the MKMapView’s delegate you will get the callback for viewForAnnotation:.

MKAnnotationView MKMapViewDelegate callback

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
static NSString *const kAnnotationReuseIdentifier = @"CPAnnotationView";

MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:kAnnotationReuseIdentifier];
if (annotationView == nil) {
    annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:kAnnotationReuseIdentifier] autorelease];
    annotationView.enabled = YES;
    annotationView.canShowCallout = YES;
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeInfoLight];

return annotationView;

You can further customize this in a custom view overriding the drawRect method, providing an image to the image property, or you could even implement an MKAnnotationView in a XIB. It is worth some experimentation.

Apple’s WeatherAnnotationView Example illustrates overriding drawRect.

I had a case where I wanted something like a standard Pin annotation, but the designer wanted a custom graphic.

I wrote a subclass of MKAnnotationView to display the graphic. The only difference is that it overrides the standard class’s image.


#import <MapKit/MapKit.h>

@interface BlipAnnotationView : MKAnnotationView

- (id)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier;



#import "BlipAnnotationView.h"

@implementation BlipAnnotationView

- (id)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
    if (self) {
        UIImage *blipImage = [UIImage imageNamed:@"blip.png"];
        CGRect frame = [self frame];
        frame.size = [blipImage size];
        [self setFrame:frame];
        [self setCenterOffset:CGPointMake(0.0, -7.0)];
        [self setImage:blipImage];
    return self;


Then in the class that displays the map, I made the class implement the MKMapViewDelegate protocol. The mapView:viewForAnnotation: method creates a new instance of BlipAnnotationView if necessary.

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
    NSLog(@"mapView:%@ viewForAnnotation:%@", mapView, annotation);
    static NSString *const kAnnotationIdentifier = @"BlipMapAnnotation";
    BlipAnnotationView *annotationView = (BlipAnnotationView *)
    [mapView dequeueReusableAnnotationViewWithIdentifier:kAnnotationIdentifier];
    if (! annotationView) {
        annotationView = [[BlipAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:kAnnotationIdentifier];
    [annotationView setAnnotation:annotation];

    return annotationView;

Finally I set the class as the delegate of the map view in awakeFromNib:

- (void)awakeFromNib
    [_theMapView setDelegate:self];

I didn’t have to change the code that positioned the annotation at all:

MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
[annotationPoint setCoordinate:[userLocation coordinate]];
[annotationPoint setTitle:label];
[_theMapView addAnnotation:annotationPoint];