UPDATE! FOUND A NEW SOLUTION!
My latest version, 2.0 of Gasmacken contains a solution to the very annoying problem with a creating a custom callout bubble to the MKMapView in the iPhone SDK. There are no way to get a callback from the MKMapView delegate when a callout bubble is opened.
A recap of what you can do with the built in callout bubble.
- MKAnnotation contains title, subtitle and coordinate
- Title must be set in the MKAnnotation to get the callout bubble
- You can customize left or right of the callout bubble (MKAnnotationView) with a UIView but not change the callout bubble design at all
One solution (almost) might be to use a property change listener for the selected value. Unfortunately, the selected property is only changed if you have a title set in the MKAnnotation, which also brings up the built in callout bubble. This is a good solution if you e.g. want to play a sound when you open up the built in callout bubble.
My solution, inspired by drawing polylines or routes on a MKMapView, has to do with adding a subview (TouchView see code in example) on top of the MKMapView and writing invisible buttons on the annotations.
#import
#import
@class UIView;
@interface TouchView : UIView {
MKMapView *mapView;
id delegate;
SEL callAtHitTest;
SEL callAtAnnotationClick;
NSMutableArray* buttonToAnnotation;
}
@property (nonatomic, assign) MKMapView * mapView;
@property (assign) id delegate;
@property (assign) SEL callAtHitTest;
@property (assign) SEL callAtAnnotationClick;
- (void) regionChange;
@end
- Selector callAtHitTest will be called every time you click on the map except for subview buttons. This method is great to use for stop follow current location updates in your code.
- Selector callAtAnnotationClick will be called when you click your annotation. This is where you make your custom callout bubble visible.
- Method regionChange must be called every time MKMapView is changed.
In a UIView sub class
- Create a TouchView, set delegate and the two selectors, callAtHitTest and callAtAnnotationClick.
- Add MKMapView as a subview to your newly created touchView. Implement MKMapViewDelegate regionDidChangeAnimated. Call method regionChanged in your TouchView class.
- Populate MKMapView with annotations.
- Add newly created MKMapView to your TouchView.
- Add TouchView to surrounding UIView.
- Call method regionChange once in TouchView.
Here is the viewDidLoad method from the example code.
- (void)viewDidLoad {
[super viewDidLoad];
touchView = [[TouchView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
touchView.delegate = self;
touchView.callAtHitTest = @selector(stopFollowLocation);
touchView.callAtAnnotationClick = @selector(annotationClicked:);
//Next we create the MKMapView object, which will be added as a subview of viewTouch
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
mapView.delegate = self;
touchView.mapView = mapView;
[touchView addSubview:mapView];
//And we display everything!
[self.view addSubview:touchView];
CLLocationCoordinate2D sweLoc = {63.048230,15.685730};
MKCoordinateSpan sweSpan = MKCoordinateSpanMake(14.208889, 24.169922);
MKCoordinateRegion sweRegion = MKCoordinateRegionMake(sweLoc, sweSpan);
mapView.region = sweRegion;
//Populate some test annotations.
NSMutableArray* annotations = [[NSMutableArray alloc] init];
CLLocationCoordinate2D coord2d = {59.33984880,18.11479872};
MyAnnotation *anno = [[MyAnnotation alloc] initWithCoords:coord2d name:@"Somewhere"];
[annotations addObject:anno];
[anno release];
CLLocationCoordinate2D coord2d1 = {65.80253606,21.67445822};
MyAnnotation *anno1 = [[MyAnnotation alloc] initWithCoords:coord2d1 name:@"Nowhere"];
[annotations addObject:anno1];
[anno1 release];
CLLocationCoordinate2D coord2d2 = {55.71919202,13.15571100};
MyAnnotation *anno2 = [[MyAnnotation alloc] initWithCoords:coord2d2 name:@"Anywhere"];
[annotations addObject:anno2];
[anno2 release];
[mapView addAnnotations:annotations];
[annotations release];
//redraw buttons
[touchView regionChange];
}
Remember to NOT set title and subtitle in your implementation of MKAnnotation. If it is set MKMapView will show the standard callout bubble if you accidentally click outside the TouchView button but inside the standard annotation in the MKMapView.
You might have to do some customization in your TouchView if you do not use the standard MKPinAnnotationView. Change CGRect coordinates for the buttons in TouchView to match your custom annotation view. Change UIButtonTypeRoundedRect to see the actual button and match it to cover your custom annotation view.
One drawback is that if you click a annotation in the TouchView it is not propagated down to the MKMapView which makes pinch zoom bit more tricky if you have many annotations. Someone out there might have a good solution for it?
That’s it. Download example for better understanding. See this post instead.

HI, thanks for the code.. but i have a dude.. in your example your show the informacion whit alert.. how i can use a view for put the data in labels etc? i try but dont works..
Just create your view and add it as a subview to MKMapView in the callAtAnnotationClick-method.
What if i want to use a custom UIImage instead of the regular pin showed where should I change the icon because I cannot find it out!.
Thanks in advanced!
Implement method
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation; and return a MKAnnotationView with your custom UIImage.Thank you very much!, it worked just fine
.
Pingback: Custom callout bubble in MKMapView, final solution! « JAKERI
Hi, Thanks this is good but this is not working perfectally with tab bar, Means map view in tab bar item. Is there any specific reason for this.
Thanks
Have you looked at my latest example. I use it as a tab bar in two of my apps so I do not see any problems with it.
HI
I have tested in Iphone OS 3.0 and 3.1. It is working fine in iphone OS 3.1 but I am facing problem in Iphone OS 3.0. when i clicked on same pin twice callout view doesn’t come after first time. Please reply waiting for your response.
Also sample is not working with iphone OS 3.0.
Thanks update source code is working with iPhone 3.0 OS
Pingback: 2010-08-01(iphone 人机设计指南/ffmpeg)