I\'m working on a MKMapView
with the usual colored pin as the location points. I would like to be able to have the callout displayed without touching the pin.>
The problem with calling selectAnnotation
from - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView
is that, as the name implies, this event is only triggered once your MapView loads initially, so you won't be able to trigger the annotation's callout if you add it after the MapView has finished loading.
The problem with calling it from - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
is that your annotation may not be on-screen when selectAnnotation
is called which would cause it to have no effect. Even if you center your MapView's region to the annotation's coordinate before adding the annotation, the slight delay it takes to set the MapView's region is enough for selectAnnotation
to be called before the annotation is visible on-screen, especially if you animate setRegion
.
Some people have solved this issue by calling selectAnnotation
after a delay as such:
-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
[self performSelector:@selector(selectLastAnnotation)
withObject:nil afterDelay:1];
}
-(void)selectLastAnnotation {
[myMapView selectAnnotation:
[[myMapView annotations] lastObject] animated:YES];
}
But even then you may get weird results since it may take more than one second for the annotation to appear on-screen depending on various factors like the distance between your previous MapView's region and the new one or your Internet connection speed.
I decided to make the call from - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
instead since it ensures the annotation is actually on-screen (assuming you set your MapView's region to your annotation's coordinate) because this event is triggered after setRegion
(and its animation) has finished. However, regionDidChangeAnimated
is triggered whenever your MapView's region changes, including when the user just pans around the map so you have to make sure you have a condition to properly identify when is the right time to trigger the annotation's callout.
Here's how I did it:
MKPointAnnotation *myAnnotationWithCallout;
- (void)someMethod {
MKPointAnnotation *myAnnotation = [[MKPointAnnotation alloc] init];
[myAnnotation setCoordinate: someCoordinate];
[myAnnotation setTitle: someTitle];
MKCoordinateRegion someRegion =
MKCoordinateRegionMakeWithDistance (someCoordinate, zoomLevel, zoomLevel);
myAnnotationWithCallout = myAnnotation;
[myMapView setRegion: someRegion animated: YES];
[myMapView addAnnotation: myAnnotation];
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (myAnnotationWithCallout)
{
[mapView selectAnnotation: myAnnotationWithCallout animated:YES];
myAnnotationWithCallout = nil;
}
}
That way your annotation is guaranteed to be on-screen at the moment selectAnnotation
is called, and the if (myAnnotationWithCallout)
part ensures no region setting other than the one in - (void)someMethod
will trigger the callout.