Custom callout bubble in MKMapView, final solution!
http://www.jakeri.net/2009/12/custom-callout-bubble-in-mkmapview-final-solution/
Posted on December 6, 2009 by admin
Once again, this post has been updated.
I was not completely satisfied with my prior solution to custom callout bubble in MKMapView due a drawback.
One drawback is that if you click an 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?
Fortunately I figured out a new solution for the problem! A much more simple solution too.
It is a combination of the property change listener solution and moving the calloutOffset off the display.
Set the calloutOffset off the display and add an observer to the selected-property.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation {
MKAnnotationView* annotationView = nil;
MyAnnotation *myAnnotation = (MyAnnotation*) annotation;
NSString* identifier = @"Pin";
MKPinAnnotationView* annView = (MKPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(nil == annView) {
annView = [[[MKPinAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
}
//Add an observer for the selected-property on the MKAnnotationView. Delegate to self.
[annView addObserver:self
forKeyPath:@"selected"
options:NSKeyValueObservingOptionNew
context:GMAP_ANNOTATION_SELECTED];
[annView setPinColor:MKPinAnnotationColorGreen];
//Set calloutOffset off screen.
CGPoint notNear = CGPointMake(10000.0,10000.0);
annView.calloutOffset = notNear;
annotationView = annView;
[annotationView setEnabled:YES];
[annotationView setCanShowCallout:YES];
return annotationView;
}
Implement the observeValueForKeyPath method. It will be triggered when the property is selected or deselected.
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{
NSString *action = (NSString*)context;
if([action isEqualToString:GMAP_ANNOTATION_SELECTED]){
BOOL annotationAppeared = [[change valueForKey:@"new"] boolValue];
if (annotationAppeared) {
[self showAnnotation:((MyAnnotationView*) object).annotation];
}
else {
NSLog(@"annotation deselected %@", ((MyAnnotationView*) object).annotation.title);
[self hideAnnotation];
}
}
}
Take a look at my new example (with standard MKPinAnnotationView) or with custom annotation view.
This entry was posted in Development, iphone and tagged callout bubble, google maps, iphone, mkannotation, mkannotationview, mkmapview, property change listener. Bookmark the permalink. ← Gasmacken 2.0 Golfkartan tillgänglig i iTunes App store →
39 Responses to Custom callout bubble in MKMapView, final solution!
- Pingback: Custom callout bubble to MKMapView in iPhone « JAKERI
-
Craig says: December 7, 2009 at 07:35
Can you show how to get detailed information into the call-out? please?
-
admin says: December 7, 2009 at 07:47
The custom callout is designed in Interface Builder. You may design this however you want. Add detailed information to your custom MKAnnotation class. Did you test the example?
Not completely sure what you mean.
-
Craig says: December 7, 2009 at 07:59
I tested your example. Very nice. I have been struggling for some time on how to pass additional properties to a call-out bubble such as phone, zip, notes, etc. The solution continues to elude me.
-
Craig says: December 7, 2009 at 23:06
I got it working following your model. Again, a really, really nice solution.
-
Craig says: December 9, 2009 at 02:13
How did you solve showing which annotation pin was in the selected state?
-
admin says: December 9, 2009 at 14:36
Method observeValueForKeyPath ofObject is the surrounding annotation view. Calling annotationView.annotation will get your custom MKAnnotation implementation.
See code in example.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
NSString *action = (NSString*)context;
if([action isEqualToString:GMAP_ANNOTATION_SELECTED]){
BOOL annotationAppeared = [[change valueForKey:@"new"] boolValue];
if (annotationAppeared) {
NSLog(@"annotation selected %@", ((MyAnnotationView*) object).annotation.title);
[self showAnnotation:((MyAnnotationView*) object).annotation];
}
else {
NSLog(@"annotation deselected %@", ((MyAnnotationView*) object).annotation.title);
[self hideAnnotation];
}
}
}
-
Craig says: December 11, 2009 at 02:24
no, I got that part. But all the annotation images are identical. It is impossible to tell “which” annotation is the selected one.
-
admin says: December 11, 2009 at 16:15
Have not tested that. I solved this issue by moving map region to the center of the display when you click on it.
It should probably be solvable with a layer above the mapview where you draw something around the annotation.
It might also be possible to replace the image (MKAnnotationView.image) in the showAnnotation method in the code above. I have not tested it.
-
admin says: December 11, 2009 at 16:31
It works. See below. Added a change to MKAnnotationView.image in th observeValueForKeyPath.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
NSString *action = (NSString*)context;
if([action isEqualToString:GMAP_ANNOTATION_SELECTED]){
BOOL annotationAppeared = [[change valueForKey:@"new"] boolValue];
if (annotationAppeared) {
NSLog(@"annotation selected %@", ((MyAnnotationView*) object).annotation.title);
[self showAnnotation:((MyAnnotationView*) object).annotation];
((MyAnnotationView*) object).image = [UIImage imageNamed:@"icon-sel.png"];
}
else {
NSLog(@"annotation deselected %@", ((MyAnnotationView*) object).annotation.title);
[self hideAnnotation];
((MyAnnotationView*) object).image = [UIImage imageNamed:@"icon.png"];
}
}
}
-
Craig says: December 12, 2009 at 03:31
That worked perfectly. I even added code to (showAnnotation) to center the annotation when clicked.
I have a new question: suppose you wanted to show an “expanded” detail view linked from the small annotation view that pops up. I added a “more info” button to the small annotation overlay and linked to a new View Controller. But how do you transfer the annotation data to the next view controller?
I have not seen another post out there like this one. It is very useful.
-
Matthew says: January 4, 2010 at 22:55
Wondering how you might be able to customize the pins. Standard customization does not seem to be working for me.
Also, wondering like @Craig, above, how you might push a new view controller from the annotation view.
tia
-
admin says: January 12, 2010 at 15:10
Sorry for my late answer.
Just pass a reference to your MKAnnotation (set a property) containing information to the newly created view controller before you present it.
I am not sure I understand what you mean by customize the pins? use another image?
Then follow standard code from apple using a custom MKAnnotationView.
-
Matthew says: January 12, 2010 at 23:12
I have tried countless ways at this point to change the pin, which works in my standard maps, but does not seem to do anything to change the pins in this demo.
It is a great technique – thanks for sharing.
-
admin says: January 12, 2010 at 23:23
I updated post with an example for you. Custom MKAnnotationView
-
Matthew says: January 13, 2010 at 02:11
Awesome. Thanks for taking the time to help me out and share your knowledge.
-
Sonali says: January 14, 2010 at 14:18
Very nice post, works very well.
Thanks
-
Matthew says: February 10, 2010 at 22:09
Do you have any other leads on learning more about KVO in relation to mapkit; pulling detailed information and passing it onto other views? Not really gleaning that from the Apple docs – perhaps it is just me
-
Ujjwal says: February 18, 2010 at 17:46
Thanks a ton Jacob for this code. It was real help.
I integrated your code with some existing one and am stuck at one issue – can you please take a look at
http://stackoverflow.com/questions/2289731/iphone-warning-in-cyclic-import-in-mkannotation-method-not-found
Basically I am trying to add a disclosure button to MoreInfoView class and on click push another view in the nav controller.
I’d really appreciate your help. Thanks a lot in advance.
-
Sijo says: March 24, 2010 at 14:11
Thanks for this great post.. i just need to add more details in MKPinAnnoataionView like Title,Address,Description,date, an image etc.. But its View should look like default MKPinannotation. I need that default black transparent bubble with the details…can we do anything in default MKPinannoation ? something like rightCalloutAccessoryView or leftCalloutAccessoryView ? .. but when am using this it getting located at left or Right side of PIn..thanks in advance
-
John says: April 5, 2010 at 01:06
I did not see any code to forward pinch-zoom event from your TouchView to your map view. We’re you able to get pinch zoom to work on your TouchView, so that you can zoom your MKMapView? Thanks
-
admin says: April 5, 2010 at 20:20
Yes. Everything works as the built in solution.
TouchView is only used to catch deselection of tbe custom annotation. The original annotationview is actually visible if you have a really large iphone screen.
CGPoint notNear = CGPointMake(10000.0,10000.0); self.calloutOffset = notNear;
-
John says: April 6, 2010 at 05:17
Cool. My soln almost works. I’ll adapt to yours and see how that works out. Thanks for sharing.
-
Chris says: April 28, 2010 at 17:00
When i try this with OS4 the map View goes crazy to the point 10000.0,10000.0 where the original annotationview is.
It only works when i try this:
CGPoint notNear = CGPointMake(1.0,1.0);
self.calloutOffset = notNear;
But then i have both annonationviews on screen.
Do you have any solution for this? I only have an iPod touch to test and i can’t go back from beta.
-
admin says: April 28, 2010 at 19:13
I have not have the time to test in OS4 yet. If you have any solution please mail me.
OS4 is still in NDA so I can not say to much.
-
Lifey says: May 4, 2010 at 03:55
There seems to be a problem with your solution on iPhoneOS3 simulator (and therefore most likely on the iPhoneOS3 device, though I haven’t checked): If the annotation is held for around a second or two, it zooms to the location of the callout bubble (which in your example is quite far away!) Do you have any ideas on how to remedy this issue?
-
admin says: May 4, 2010 at 09:29
I did not know that. Have to take a look at it.
-
admin says: May 9, 2010 at 22:53
I think I have found a solution working for iPhoneOS 3.0, 3.1, 3.2 and 4.0. Both iPad and iPhone. Will try to make new post in a couple of days.
-
dc says: May 13, 2010 at 21:43
Have you any idea of a way of releasing the observationInfo so that it does not leak when an annotation is removed?
Much thanks for the sample code.
-
adam says: May 14, 2010 at 10:58
I love your solution for this, elegant and cunning.
Really disappointed about the news that it’s not working on OS 4 beta, though. I guessed that might happen (Apple often does things like this – if you’ve got something visible, sooner or later they “helpfully” change the system behaviour to show it).
Did you find a new solution (version 3 of this fix, I guess
) ? -
admin says: May 14, 2010 at 12:04
I think so. Will try to post tomorrow. Only thing I have not fixed is the leaking of observationinfo.
- Pingback: Revisited – Custom callout bubble in MKMapView, final solution! « JAKERI
-
Devin Foley says: July 6, 2010 at 08:38
I was able to get this working in iOS4 by commenting out the notNear stuff and setting canShowCallout to NO:
//CGPoint notNear = CGPointMake(10000.0,10000.0);
//annView.calloutOffset = notNear;
…
[annotationView setCanShowCallout:NO];
-
admin says: July 6, 2010 at 09:42
Look at my latest post instead.
-
Offbeat Attractions says: August 10, 2010 at 18:17
This is AWESOME. I’ve been trying to add an image on top of the marker which wasn’t working – until I found this. Thanks for sharing the code. It works perfectly
-
Malek says: May 10, 2011 at 01:45
Hi, please, have you any tutorial which shows how to move data from a view to another to show them when i select the UIButtonTypeDetailDisclosure button of the pin ? my purpose is that when i click the detail button on the pin, i will be redirect to another view in which i place all details of the pin selected, please help, i really need step-by step tutorial,i have maked the pins with the detail button, and the data are retrieved from web-service, but i don’t know how to tell view “here the data of this pin, display it”.
-
ambu.sangoli says: May 21, 2011 at 22:01
2011-05-22 01:14:43.415[6106:307] stopFollowLocation called. Good place to put stop follow location annotation code.
2011-05-22 01:14:43.420[6106:307] stopFollowLocation called. Good place to put stop follow location annotation code.
2011-05-22 01:14:43.424[6106:307] stopFollowLocation called. Good place to put stop follow location annotation code.
2011-05-22 01:14:43.885[6106:307] annotation deselected (null)
Please help i am getting all working but not showing any text and in console the above it is showing
-
Simon Burfield says: July 15, 2011 at 17:37
Hello there, I downloaded by examples and ran it up on 4.2 in simulator and it does some very odd things when you click the pin and I end up with different views show?