views:

1824

answers:

3

With the MKMapView there's an option called "Show users current location" which will automatically show a users location on the map.

I'd like to move and zoom to this location when it's found (and if it changes).

The problem is, there doesn't appear to be any method called when the user location is updated on the map, so I have nowhere to put the code that will zoom/scroll.

Is there a way to be notified when an MKMapView has got (or updated) the user location so I can move/zoom to it? If I use my own CLLocationManager the updates I get do not correspond with the updates of the user marker on the map, so it looks silly when my map moves and zooms seconds before the blue pin appears.

This feels like basic functionality, but I've spent weeks looking for a solution and not turned up anything close.

A: 

No problem... Inside the viewDidLoad method of your UIViewController subclass that has the MKMapView add this (assuming your MKMapView is named map):

CLLocation *location = [[[CLLocation alloc] initWithLatitude:map.centerCoordinate.latitude longitude:map.centerCoordinate.longitude] autorelease]; //Get your location and create a CLLocation
MKCoordinateRegion region; //create a region.  No this is not a pointer
region.center = location.coordinate;  // set the region center to your current location
MKCoordinateSpan span; // create a range of your view
span.latitudeDelta = BASE_RADIUS / 3;  // span dimensions.  I have BASE_RADIUS defined as 0.0144927536 which is equivalent to 1 mile
span.longitudeDelta = BASE_RADIUS / 3;  // span dimensions
region.span = span; // Set the region's span to the new span.
[map setRegion:region animated:YES]; // to set the map to the newly created region
Dustin Pfannenstiel
I tried pretty much this, but the problem seemed to be that this code runs *before* the users location has been determined.
Danny Tuppeny
A: 

Copy the code in the viewWillAppear method.

FenchKiss Dev
Did you try this?The problem is that the GPS doesn't return a location for many seconds. The viewWillAppear method still fires way too early - it fires when the map is drawn. I need something that fires when the user location pin is drawn (and moved).I find it quite amazing that this functionality might not exist :/
Danny Tuppeny
Actually, no. But I had a similar problem.However, for the first appearence you could use:(MKAnnotationView *)mapView:(MKMapView *) viewForAnnotation:(id <MKAnnotation>)It is called when the view needs to draw the annotation view. You will get a annotation object of type MKUserLocation if the view is requesting the annotation view for the user location.I don't know if it is be called when the user location moves though.
FenchKiss Dev
I was thinking about that. It seems mad to me that this isn't easier.Need to do the same thing in another app, so I'm going to play with the settings. I wonder if I can choose the same settings on a CLLocationManager as the MKMapView is using, that maybe the map and my own delegates will fire together with the same data. Fingers crossed...
Danny Tuppeny
+9  A: 

You have to register for KVO notifications of userLocation.location property of MKMapView.

To do this, put this code in viewDidLoad: of your ViewController or anywhere in the place where your map view is initialized.

[self.mapView.userLocation addObserver:self  
        forKeyPath:@"location"  
           options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)  
           context:NULL];

Then implement this method to receive KVO notifications

-(void)observeValueForKeyPath:(NSString *)keyPath  
                     ofObject:(id)object  
                       change:(NSDictionary *)change  
                      context:(void *)context {  

    if ([self.mapView isUserLocationVisible]) {  
        [self moveOrZoomOrAnythingElse];
        // and of course you can use here old and new location values
    }
}

This code works fine for me.
BTW, self is my ViewController in this context.

ddnv
I've never used KVO before, so had to Google. Looks like this will do exactly what I need - thank you!
Danny Tuppeny
There is a problem in this code. It only works if the user location is already somewhere on the visible on the map. [self.mapView isUserLocationVisible] is only true if the user location is within the current map region. Instead the line should read: self.mapView.showsUserLocation
Felix
Otherwise: thank you for this very elegant solution.
Felix
@Felix that doesn't seem to be the case for me
culov
For those who are confused on how to implement: [self moveOrZoomOrAnythingElse];Just add the category at this link: http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/to your code and then replace the line:[self moveOrZoomOrAnythingElse];with [self.mapView setCenterCoordinate:self.mapView.userLocation.location.coordinate zoomLevel:14 animated:YES];It works like a charm.
Vibhor Goyal