开发者

How can I set MKMapView's region span dynamically so that it doesn't "snap" back to the initial Region upon redrawing the map?

开发者 https://www.devze.com 2023-03-15 20:21 出处:网络
I am working with a MKMapview and I am having a problem with the zoom level and the region span. It would seem when the MKMapView is refreshed it resets the region to the values that have been hardco

I am working with a MKMapview and I am having a problem with the zoom level and the region span.

It would seem when the MKMapView is refreshed it resets the region to the values that have been hardcoded when I initially installed them. I am keeping track of the user's location and with any changes in the location of the phone the map should update via the CLLocationManagerDelegate and the delegate method listed below.

Currently I have this in the locationManager:didUpdateToLocation:fromLocation:

    MKCoordinateSpan span;
    span.latitudeDelta =  0.8;  
    span.longitudeDelta = 0.8;     
    MKCoordinateRegion region;
    region.center = newLocation.coordinate;
    region.span = span;
    [self.MyMapView setRegion:region animated:NO];

I have also tried putting similar code in the viewDidLoad: to no avail. My thinking is that I could somehow set the region dynamically in the

-(void)mapView:(MKMapView *)mapView regi开发者_如何学PythononDidChangeAnimated:(BOOL)animated

delegate method I could sidestep this issue entirely but I am not exactly sure how I should do that.

Ultimately I'd just like to have the map stop "snapping" back to the above span. Thanks in advance.


If you're trying to keep the map centered on the user's current location, first decide whether you want to use:

  • the map view's userLocation property and the map view's delegate method mapView:didUpdateUserLocation:, or
  • the CLLocationManager and its delegate method locationManager:didUpdateToLocation:fromLocation:

With either one, in viewDidLoad, you should just set the map view's initial region including center (using some default coordinate) and span. The user's location will be unlikely to be available immediately in viewDidLoad as it can take a few seconds to acquire.

Trying to use userLocation before its set may cause an exception when setting the region with that value.

If using the map view's userLocation, then:

  • in viewDidLoad or IB, set mapView.showsUserLocation to YES
  • in the mapView:didUpdateUserLocation: method, do mapView.centerCoordinate = userLocation.location.coordinate; (or use setCenterCoordinate:animated:)
  • recommend also implementing mapView:didFailToLocateUserWithError: to handle or at least become aware of failures

If using the CLLocationManager, then:

  • in viewDidLoad, do [locationManager startUpdatingLocation];
  • in the locationManager:didUpdateToLocation:fromLocation: method, do mapView.centerCoordinate = newLocation.coordinate; (or use the animated method)
  • recommend also implementing locationManager:didFailWithError: to handle or at least become aware of failures


I was able to solve this problem by creating a UIViewController subclass to hold the MKMapView instance. I restore the mapView's span in loadView, and then call [mapView setUserTrackingMode:...] in the VC's viewWillAppear method.

I saw the behavior the OP described in a previous implementation, where I created a VC and a `MKMapView' instance on the fly and then pushed it onto my navigation controller. I was never able to both set the span and set user tracking to follow the user without the span getting lost. I did some debugging and even saw that the original span values were being discarded when the view displayed, so I think it had something to do with setting span or setting the user tracking mode without the view having been displayed. At any rate, organizing the code as above solved the problem.

Here are the relevant bits:

// ===== mainVC.h =====
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface MapVC : UIViewController <MKMapViewDelegate>
@end

// ===== mainVC.m =====   
static MapVC *map = nil;

- (void)mapAction {
    UINavigationController *nav = [self navigationController];

    // map VC is a singleton
    if (!map) map = [[MapVC alloc] init];

    [nav pushViewController:map animated:TRUE];
}


// ===== MapVC.m =====
- (void)loadView {
    mapView = [[MKMapView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [mapView setDelegate:self];
    MKCoordinateSpan span = MKCoordinatSpanMake(storedLatitudeDelta, storedLongitudeDelta);
    [mapView setRegion:MKCoordinateRegionMake(storedCenter, span)];
    [self setView:mapView];
}

- (void)viewWillAppear:(BOOL)animated {
    [mapView setUserTrackingMode:MKUserTrackingModeFollow animated:TRUE];
}

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    MKCoordinateSpan mySpan = [mapView region].span;
    storedLatitudeDelta = mySpan.latitudeDelta;
    storedLongitudeDelta = mySpan.longitudeDelta;
}

I pruned that out of a bigger project, so let me know if you see any typos, but that's the gist of it.

0

精彩评论

暂无评论...
验证码 换一张
取 消