Customize the MKAnnotationView callout
Asked Answered
O

3

43

I want to create a custom MKAnnotationView callout as shown in this image. I have tested several solutions but they only allow customization of the left/right images and title/subtitle. Can anybody please give me some source code or tutorial link for it?

Currently I am clueless. Please help.

enter image description here

Ought answered 5/11, 2011 at 7:39 Comment(3)
I think that this is just a custom view with a custom pin, what's your real problem?Chromic
Very Good question.. It helps me also.. Thanks a lot Jennis..Crosby
Sample demo - #27520017Basuto
H
50

I understand you want a pin with a custom callout.

We can't create a custom callout, but we can create an annotation with a completely customized view. So the trick is to add a second annotation when the first is selected, and make the 2nd annotation view look like a callout bubble.

This is the solution posted by users djibouti33 and jacob-jennings in the answer: MKAnnotationView - Lock custom annotation view to pin on location updates, which in turn is based in a blog post from Asynchrony Solutions. For explanation purposes, here is some UML from a forked project: Annotation with custom XIB

This is a big hack, but also the cleanest way I've seen to implement custom annotations.

Start with a NSObject "Content" class which has a coordinate, the class of the callout view to use (in the UML is AnnotationView, but you can create more and set them here), and a dictionary of random values with the title, photo url, etc. Use this class to initialize a MKAnnotation "Annotation" object.

#import <MapKit/MapKit.h>
@interface Content : NSObject
@property (nonatomic,assign) CLLocationCoordinate2D coordinate;
// ...

@interface Annotation : NSObject <MKAnnotation, AnnotationProtocol>
-(id) initWithContent:(Content*)content;
// ...

The Annotation implements AnnotationProtocol to announce it wants to handle the creation of its own MKAnnotationView. That is, your MKMapViewDelegate should have code like this:

- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id<MKAnnotation>)annotation 
{
    // if this is a custom annotation, delegate the implementation of the view
    if ([annotation conformsToProtocol:@protocol(AnnotationProtocol)]) {
        return [((NSObject<AnnotationProtocol>*)annotation) annotationViewInMap:mapView];
    } else {
        // else, return a standard annotation view
        // ...
    }
} 

The view returned will be of type AnnotationView, which implements AnnotationViewProtocol to announce that it wants to handle selection/deselection. Therefore, in your map view controller, the methods mapView:didSelectAnnotationView: and mapView:didDeselectAnnotationView: should delegate in a similar way to what we saw before.

When the annotation is selected, a second annotation (CalloutAnnotation) is added, which follows the same behaviour, but this time the view returned (CalloutView) is initialized from a XIB, and contains Core Graphics code (in BaseCalloutView) to animate and replicate a callout.

The initializer of the CalloutView class:

- (id)initWithAnnotation:(CalloutAnnotation*)annotation
{
    NSString *identifier = NSStringFromClass([self class]);
    self = [super initWithAnnotation:annotation reuseIdentifier:identifier];
    if (self!=nil){
        [[NSBundle mainBundle] loadNibNamed:identifier owner:self options:nil];
        // prevent the tap and double tap from reaching views underneath
        UITapGestureRecognizer *tapGestureRecognizer = ...
    }
    return self;
}

To be able to push another view controller from the callout view I used notifications.

The SO answer I linked at the top contains two complete projects implementing this code (class names may differ). I have another project using the UML above at https://github.com/j4n0/callout.

Hatteras answered 5/11, 2011 at 9:30 Comment(2)
Hello, Thanks for the wonderful work you have done. I'm trying to create an annotation why two buttons in it. When I'm clicking on the button, the methode handleTouch of my CalloutView subclass is called. But the sender is an UITapGestureRecognizer with the annotation in the view property I was expected to have my button into the sender.view? Is it a well known issue. Or I'm I doing something wrong ?Henryson
@amitgupta Ask specific questions. Never ask if anyone can help you without describing your problem in detail. See mattgemmell.com/what-have-you-triedHatteras
C
1

I added custom UIButton in MKAnnotationView. And on click of that button I have shown popOver with rootViewController with the view similar as you have shown above.

Cask answered 23/4, 2012 at 9:53 Comment(0)
F
1

I know this question is from 2011 but for people who still find it in a search: In iOS 9 you have MKAnnotationView.detailCalloutAccessoryView which entirely replaces the standard callout.

Facient answered 17/10, 2018 at 12:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.