问题
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 regionDidChangeAnimated:(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.
回答1:
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 methodmapView:didUpdateUserLocation:
, or - the
CLLocationManager
and its delegate methodlocationManager: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
toYES
- in the
mapView:didUpdateUserLocation:
method, domapView.centerCoordinate = userLocation.location.coordinate;
(or usesetCenterCoordinate: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, domapView.centerCoordinate = newLocation.coordinate;
(or use the animated method) - recommend also implementing
locationManager:didFailWithError:
to handle or at least become aware of failures
回答2:
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.
来源:https://stackoverflow.com/questions/6511574/how-can-i-set-mkmapviews-region-span-dynamically-so-that-it-doesnt-snap-back