Callout bubble in MKMapView
Posted by eric | Filed under Lab Work, Personal

All i needed was some custom text in the call out bubble, and then i needed that bubble to appear just as the pin dropped. i spent hours on something that seemed so simple…and actually , it is simple.
There are a few unknonwns about the MKMap framework. Namely, how to customize the bubble in the callout. A few terms that may be helpful since Apple did not do a great job on explaining this:
MKAnnotation: essentially, this is the callout bubble.
MKPinAnnotationView : this is the pin that drop. Can be just about any UIImage or UIView, and does not have to drop (animiated:NO)
CLLocationCoordinate2D: it’s a mouthful, but this is essentially a C structure that contains the lat/long (point) of where you are mapping
MKCoordinateRegion: in Apple’s own words = “A structure that defines which portion of the map to display.”. Ok, i’ll give them that one. Once you define your CLLocationCoordinate2D, you can pass it’s properties to this guy, and manage how much of your map you will be showing. This Object allows you to set the zoom level (”span”) on loading your map. It’s a bit of reverse psychology (at least for me)…the greater the span, the “higher your birdseye”….lower the span, the closer to your CLLocationCoordinate2D point. (IE: if you have 0 span, think of this as the point itself).
MKMapView : This is where it’s all happening. Remember to conform to the delegate protocol in your class before doing anything:
Ok, so some code…in my example i have a wrapper class to house all this fun stuff. The class contains my webview, delegate methods , and includes the most important part: a custom class to inherit from MKAnnotation. This is necessary to access the title/subtitle . The guys at InvasiveCode solved this for me (link below).
#import #import @interface MyAnnotation : NSObject { NSString *title; NSString *subtitle; CLLocationCoordinate2D coordinate; } @property(nonatomic,assign) CLLocationCoordinate2D coordinate; @property(nonatomic,retain) NSString *title; @property(nonatomic,retain) NSString *subtitle; @end
implementation is really nothing, but necessary
#import "MyAnnotation.h" @implementation MyAnnotation @synthesize title; @synthesize subtitle; @synthesize coordinate; -(void) dealloc { [title release]; [subtitle release]; [super dealloc]; } @end
Finally, in my MapViewController, i have a method i call when i am ready to make it all come together…
-(void) assignLocation:(NSDictionary *)locationDictionary { mappy =[[MKMapView alloc] initWithFrame:CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height)]; mappy.showsUserLocation = NO; mappy.delegate = self; [self.view addSubview:mappy]; CLLocationCoordinate2D thislocation = mappy.userLocation.coordinate; thislocation.latitude = [[[locationDictionary objectForKey:@"Venue"]objectForKey:@"lat"] floatValue]; thislocation.longitude = [[[locationDictionary objectForKey:@"Venue"]objectForKey:@"lng"] floatValue]; MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } }; region.center.latitude = thislocation.latitude; region.center.longitude = thislocation.longitude; region.span.longitudeDelta = 0.01f; region.span.latitudeDelta = 0.01f; [mappy setRegion:region animated:YES]; [mappy regionThatFits:region]; //add my custom annotation, with access to title/subtitle MyAnnotation *anote = [[MyAnnotation alloc] init]; anote.coordinate = thislocation; anote.title =[[locationDictionary objectForKey:@"Venue"]objectForKey:@"name"]; anote.subtitle = [[locationDictionary objectForKey:@"Venue"]objectForKey:@"address"]; [mappy addAnnotation:anote]; }
Cool…but what about getting that callout to “pop on drop”? Yeah, lets do that too….becuase you are conforming to the map delegate , you have access to a few useful methods. Namely: viewForAnnotation and mapViewDidFinishLoadingMap .
-(void)displayExtraDetailsFromInfoButton { } - (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id ) annotation { MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"currentloc"]; annView.animatesDrop=TRUE; UIButton *addButton = [UIButton buttonWithType:UIButtonTypeInfoLight]; [addButton addTarget:self action:@selector(displayExtraDetailsFromInfoButton) forControlEvents:UIControlEventTouchUpInside]; annView.rightCalloutAccessoryView = addButton; [annView setCanShowCallout:YES]; [annView setSelected:YES animated:YES]; return annView; } - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView { for (id currentAnnotation in mapView.annotations) { [mapView selectAnnotation:currentAnnotation animated:YES]; } }
special thanks to invasive code – the MKAnnotation was everything i needed to get this map interface working like i wanted
One Response to “Callout bubble in MKMapView”
-
jimothy Says:
December 15th, 2009 at 2:22 pmThanks for the code, this looks useful. But may I suggest a different color scheme? There’s not enough contrast between the text and the background, making this rather difficult to read.