Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wanted: How to reliably, consistently select an MKMapView annotation

After calling MKMapView's setCenterCoordinate:animated: method (without animation), I'd like to call selectAnnotation:animated: (with animation) so that the annotation pops out from the newly-centered pushpin.

For now, I simply watch for mapViewDidFinishLoadingMap: and then select the annotation. However, this is problematic. For instance, this method isn't called when there's no need to load additional map data. In those cases, my annotation isn't selected. :(

Very well. I could call this immediately after setting the center coordinate instead. Ahh, but in that case it's possible that there is map data to load (but it hasn't finished loading yet). I'd risk calling it too soon, with the animation becoming spotty at best.

Thus, if I understand correctly, it's not a matter of knowing if my coordinate is visible, since it's possible to stray almost a screenful of distance and have to load new map data. Rather, it's a matter of knowing if new map data needs to be loaded, and then acting accordingly.

Any ideas on how to accomplish this, or how to otherwise (reliably) select an annotation after re-centering the map view on the coordinate where that annotation lives?

Clues appreciated - thanks!

like image 636
Joe D'Andrea Avatar asked Aug 10 '09 19:08

Joe D'Andrea


4 Answers

I ran into the same problem, but found what seems like a reliable and reasonable solution:

  1. 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];
    }
    
  2. 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.

like image 165
John Blackburn Avatar answered Nov 02 '22 21:11

John Blackburn


A more consistent way than using a fixed timeout is to listen to the regionDidChange callback. Set the center coordinate of the map to the desired annotation, and when the regionDidChange method is called, then select the annotation in the center, to open the callout.

Here's a little video I took of the thing running randomly between 5 pins.

First, goto the center coordinate of the annotation. Let's say the annotation object is named thePin.

- (void)someMethod {
    [map setCenterCoordinate:thePin.coordinate animated:YES];
}

Then in the regionDidChange method, select this annotation.

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    [map selectAnnotation:thePin animated:YES];
}
like image 7
Anurag Avatar answered Nov 02 '22 21:11

Anurag


Well just FYI, this is what the docs say,

If the specified annotation is not onscreen, and therefore does not have an associated annotation view, this method has no effect.

So if I want to call setCenterCoordinate:animated: or setRegion:animated: and then I want to select the annotation by calling, selectAnnotation:animated: , the annotation won't get selected and the callout won't appear beacause of the exact same reason mentioned above in docs, So the way it would be great to have something like, setCenterCoordinate:animated:ComletionBlock but its not there..! The way that worked for me is as below,

 [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.mapView setCenterCoordinate:location.coordinate animated:YES];
    } completion:^(BOOL finished) {
        [self.mapView selectAnnotation:location animated:YES];
    }];

This will give you a completion block and u can use that to select the annotation.

like image 5
akshaynhegde Avatar answered Nov 02 '22 20:11

akshaynhegde


What has worked for me was calling selectAnnotation:animated: from the mapView:didAddAnnotationViews: method:

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views;
{
    [mapView selectAnnotation:[[mapView annotations] lastObject] animated:YES];
}

Apple documentation on the same here.

Note that I only had one annotation on the map so [[mapView annotations] lastObject] was fine for my purposes. Your mileage may vary.

like image 4
szzsolt Avatar answered Nov 02 '22 20:11

szzsolt