HowTo initialise MKMapView with a given user location?

53,784

Solution 1

Yes, it is possible to have a separate location manager object and assign its value to the mapview (BTW, I'm using '=' below as list prefix to prevent the SO code-formatter from borking).

= In your UIViewController maintain two separate properties: one to a MKMapView and one to a CLLocationManager.

= Create a XIB file with the MKMapView and any other window chrome you want. Connect the outlets to the controller propeties. Make sure MKMapView does NOT follow user location.

= Have the UIViewController implement the CLLocationManagerDelegate protocol--especially the locationManager:didUpdateToLocation:fromLocation: method which will be called whenever a new location value is available. We'll be setting the controller as the delegate for the location manager.

= In the viewController's loadView method, load the NIB with the MKMapView in it. To give user feedback you may want to put up a UIActivityIndicatorView spinner and set it to startAnimating. Then you start with:

self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
self.locationManager.distanceFilter = 10; // or whatever
[self.locationManager startUpdatingLocation];

= In locationManager:didUpdateToLocation:fromLocation: check to see if the event was updated since the last N seconds. Then tell the location manager to stop updating, the spinner to stop animating, and get the lat/long data and assign it to the map view along with a view span and region so it zooms and centers to the right place.

= Now here's the tricky part: the blue marble 'throbber' is a feature of the mapview tracking user location. You'll have to momentarily 'fake it' until the real one kicks in (or just use a separate marker for the current location and maintain its position yourself). Personally I'd go with the blue marble that the user is familiar with.

= To make it so it shows right at startup you will need to create a custom MKAnnotationView with just the blue marble graphic added at the location returned by the location manager. This means taking a snapshot of a Mapview with the location showing, then photoshopping just the blue marble out and using it as the image for a custom annotation view.

= If you want it to actively follow the map, you can enable the userlocation tracking of the mapview and when it gets the actual data, you hide your previously set marker and let the mapview do the updating. The other option is to allow the existing location manager to continue receiving updates every second or so and update the position of the blue marble annotation yourself.

= To let the mapview's own userLocation do the updating add to viewDidLoad:

[self.map.userLocation addObserver:self 
forKeyPath:@"location" 
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) 
context:NULL];
self.map.showsUserLocation = YES; // starts updating user location

= Implement observeValueForKeyPath. It gets called when the location attribute of the mapview's userlocation has a value:

-(void)observeValueForKeyPath:(NSString *)keyPath 
      ofObject:(id)object 
        change:(NSDictionary *)change 
       context:(void *)context 
{
     if ([self.map isUserLocationVisible]) {
         [self.locationManager stopUpdatingLocation];
         self.ownBlueMarble.hidden = YES;
     }
     // The current location is in self.map.userLocation.coordinate
}

= To avoid the warm-up delay in showing current location, keep a reference to the viewController containing the map and the location manager so it doesn't go away (it's a bit of a memory hog but if you release it you'll have to wait again until MapView loads the tiles and is ready to go).

= In viewWillLoad you can stuff the last known location into the custom bluemarble annotation and show it. Toggle on/off the userLocation tracking and when you get the notification the same hide-the-annotation-show-the-real-marble trick will work. The mapview's own location manager kicks in and when it has the data, you can make your annotation marker disappear.

= You might want to implement the viewController's viewWillDisappear method and manually turn off userLocation tracking on the mapview so it's off by default the next time the view is brought up. You'll also want to get the last known userLocation and save it for the next get-go. That way, you can do all the positioning marker-juggling in the viewWillAppear method and not have to worry about userLocation interfering until you're ready for it.

Good luck.

Solution 2

In your controller:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    CLLocationCoordinate2D coord = {latitude: 37.423617, longitude: -122.220154};
    MKCoordinateSpan span = {latitudeDelta: 1, longitudeDelta: 1};
    MKCoordinateRegion region = {coord, span};
    [mapView setRegion:region];
}

When map appears it's going to be centered close to Palo Alto

Share:
53,784

Related videos on Youtube

jantimon
Author by

jantimon

https://github.com/jantimon/html-webpack-plugin Follow me: @jantimon

Updated on May 12, 2020

Comments

  • jantimon
    jantimon about 4 years

    My app knows the current user position (CoreLocation.framework). As soon as the user opens a new MapView his iPhone starts searching for the current position again. Is it possible to skip that or to change the first user position for mkMapView?

    Edit:

    Is it possible to overwrite MKMapView and use an other LocationManager?

  • jantimon
    jantimon over 14 years
    that is not what I need. I want to change the position of the blue position indicator ("current location").
  • zakovyrya
    zakovyrya over 14 years
    userLocation is readonly property, I doubt you can do something about it. The only legal way would be to disable blue indicator that Apple provides and write your own, which is kind of pointless
  • jantimon
    jantimon over 14 years
    no it is not about the region but about the position indicator
  • jantimon
    jantimon over 14 years
    The thing is that the user position is not shown or it is shown wrong for the first 10 seconds a new MKMapView is shown. After these 10 seconds everything is fine. However as I know the position I would love to skip those 10 seconds.
  • jantimon
    jantimon over 14 years
    Thanks Ramin. This is not the expected solution however I guess it is the closest existing one.
  • Ramin
    Ramin over 14 years
    Yes, it would have been so much easier if they allowed us to set userLocation on a mapview to an initial value... or better still allow use of an existing CLLocationManager instance instead of creating their own... but unfortunately they don't.
  • renevdkooi
    renevdkooi almost 11 years
    maybe old, but if someone reads this, you should get the user location when starting the app, which will start the GPS to locate the user. That way by the time the user opens the map, he/she has been located already. pS: it's pretty normal for 10 seconds, even the google maps app takes a few seconds after you turn on location
  • Nick T
    Nick T about 10 years
    Set a 500m x 500 m region [mapView setRegion:MKCoordinateRegionMakeWithDistance(CLLocationCoord‌​inate2DMake(54.23349‌​8f, 1.99375f), 500, 500)];