Wanted: How to reliably, consistently select an MKMapView annotation
I ran into the same problem, but found what seems like a reliable and reasonable solution:
Implement the delegate method mapView:didAddAnnotationViews:. When I tried selecting the annotation directly within the delegate method, the callout dropped with the pin! That looked odd, so I add a slight delay of a half-second.
-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
[self performSelector:@selector(selectInitialAnnotation)
withObject:nil afterDelay:0.5];
}Select the initial annotation as you'd expect, but calling selectAnnotation:animated;
-(void)selectInitialAnnotation {
[self.mapView selectAnnotation:self.initialAnnotation animated:YES];
}
It seems that selectAnnotation:animated:
is not called under some conditions. Compare with MKMapView docs:
If the specified annotation is not onscreen, and therefore does not
have an associated annotation view, this method has no effect.
Why does selectAnnotation not work in this scenario?
The annotation view has to have been added before you can select the annotation.
Please see this popular question:
How to trigger MKAnnotationView's callout view without touching the pin?
How to trigger MKAnnotationView's callout view without touching the pin?
Ok, here's the solution to this problem.
To display the callout use MKMapView
's selectAnnotation:animated
method.
ios MapKit have annotation description visible on launch and not on tap
use an overlay instead of an annotation
How to use MKMapView finished loading delegate, possible finished displaying delegate?
Update: iOS7 has a new delegate which may have fixed this problem. I have not confirmed one way or the other yet.
- (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered
Pre iOS6 support:
mapViewDidFinishLoadingMap
: appears to be unreliable. I notice that it is sometimes not called at all, especially if the map tiles are already cached, and sometimes it is called multiple times.
I notice that when it is called multiple times the last call will render correctly. So I think you can get this to work if you set up a 2 second timer after the user taps save. Disable interactions so that nothing else can happen, and enable user interactions when the timer goes.
If mapViewDidFinishLoadingMap
gets called reset the timer again for 2 seconds in the future. When the timer finally goes off, get the snapshot of the map and it should be correct.
You will also want to consider the other callbacks such as mapViewDidFailLoadingMap
. Also test this on a noisy connection, since 2 seconds may not be long enough if it takes a long time to fetch the tiles.
- (void)restartTimer
{
[self.finishLoadingTimer invalidate];
self.finishLoadingTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(mapLoadingIsFinished)
userInfo:nil
repeats:NO];
}
- (void)userClickedSave
{
assert(self.saving == NO);
if (self.saving == NO) {
self.saving = YES;
assert(self.finishLoadingTimer == nil);
self.view.userInteractionEnabled = NO;
[self restartTimer];
}
}
- (void)mapLoadingIsFinished
{
self.finishLoadingTimer = nil;
[self doSnapshotSequence];
self.saving = NO;
self.view.userInteractionEnabled = YES;
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView
{
if (self.saving) {
[self restartTimer];
}
}
Handling overlapping MKAnnotationView(s)
I ended up working with zPosition
:
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"tag" ascending:NO];
NSArray *sortedViews = [views sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
// Set zPosition
for (MKAnnotationView *annotationView in sortedViews) {
annotationView.layer.zPosition = ++_zPositionForAnnotationViews;
}
// Do whatever
// . . .
}
- (void)mapView:(MKMapView *)aMapView didSelectAnnotationView:(MKAnnotationView *)view {
NSLog(@"The annotation tapped is: %@", view.annotation.title);
// Ignore tap on user location
if ([view.annotation isKindOfClass:[MKUserLocation class]]) {
return;
}
// Update zPosition (to bring it to front)
view.layer.zPosition = ++_zPositionForAnnotationViews;
// Do whatever
// . . .
}
Where _zPositionForAnnotationViews
is a class variable.
Choose current annotation
To get the current annotations on the map you could loop like this:
MKMapView * map = [[MKMapView alloc]initWithFrame:self.view.frame];
for (MKPointAnnotation * annotation in [map annotations])
{
//Change annotation coordinate to new coordinate
}
Set first annotation in annotations
Howe said @ogres: mapView
might re-arrange the array of the Pubs
, so i had to select it from the TableView
-s array mapView.selectAnnotation(tableView.annotations.first!, animated: true)
Mapkit Annotation type when zooming in and out?
Hey veer the problem is that this method is called if the user pans the map to view another location and then comes back to the place where the annotations are plotted.
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
I have seen many sample code for map application and this in what most of the people are using.
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* AnnotationIdentifier = @"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKPinAnnotationView* pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.draggable = YES;
pinView.pinColor = MKPinAnnotationColorGreen;
return pinView;
}
return nil;
}
Related Topics
"Could Not Find Any Information for Class Named Viewcontroller"
Is It Necessary to Use [Unowned Self] in Closures of Uiview.Animatewithduration(...)
Ios: Place Uiview on Top of Uitableview in Fixed Position
Reading Long Characteristic Values Using Corebluetooth
iOS 6 Rotations: Supportedinterfaceorientations Doesn't Work
Repeating Local Notifications for Specific Days of Week (Swift 3 iOS 10)
Uiviewcontroller Prevent View from Unloading
Swift Failed with Exit Code 1 While Compiling in Xcode - Possibly Related to Bridging-Headers
Run a Swift 2.0 App Forever in Background to Update Location to Server
Swift Framework: Umbrella Header '[...].H' Not Found
How to Add a Uitoolbar Programmatically to an iOS App
Getting Video Snapshot for Thumbnail
Uitextfield - Capture Return Button Event
Can't Prevent 'Touchmove' from Scrolling Window on iOS
Calculating Tiles to Display in a Maprect When "Over-Zoomed" Beyond the Overlay Tile Set
How to Delete Derived Data and Clean Project in Xcode 5 and Later
How to Set an Title of the Currently Playing Audio in iPhone Lock Screen