I'm trying to zoom a map into the user's current location once the view loads, but I'm getting the error "** * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid Region '" when the view loads. Please can someone help?
Cheers!
- (void)viewDidLoad
{
[super viewDidLoad];
MKCoordinateRegion mapRegion;
mapRegion.center.latitude = map.user开发者_如何学运维Location.coordinate.latitude;
mapRegion.center.longitude = map.userLocation.coordinate.longitude;
mapRegion.span.latitudeDelta = 0.2;
mapRegion.span.longitudeDelta = 0.2;
[map setRegion:mapRegion animated: YES];
}
did you set showsUserLocation = YES
? MKMapView
won't update the location if it is set to NO
. So make sure of that.
It is very likely that the MKMapView
object doesn't have the user location yet. To do right, you should adopt MKMapViewDelegate
protocol and implement mapView:didUpdateUserLocation:
map.delegate = self;
...
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = 0.2;
mapRegion.span.longitudeDelta = 0.2;
[mapView setRegion:mapRegion animated: YES];
}
As with Deepak's answer, except you could set the span more elegantly:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
MKCoordinateRegion mapRegion;
mapRegion.center = map.userLocation.coordinate;
mapRegion.span = MKCoordinateSpanMake(0.2, 0.2);
[map setRegion:mapRegion animated: YES];
}
You don't want to update this stuff inside userDidUpdateLocation if there is the possbility that the user will want to scroll the map. If you put that code in the mentioned method, the user will not be able to scroll the map because the function will be called and center the map back to the current location.
By far the easiest way is to use mapView.showAnnotations in didUpdateUserLocation:
func mapView(mapView: MKMapView!, didUpdateUserLocation userLocation: MKUserLocation!) {
mapView.showAnnotations([userLocation], animated: true)
}
That's all!
MKUserLocation conforms to the MKAnnotation protocol. Pass the userLocation as an array, the showAnnotations method will let the mapView zoom in on a region plus padding spanning the array of MKAnnotations,in this case it's just the userLocation. Works for me.
If you only want to zoom in once, use a initialUserLocation property to check whether the initial property was already set. I don't like using dispatch_once at all for that sort of thing
Here is @Deepak's answer in Swift 3 for iOS 10:
extension ViewController: MKMapViewDelegate
{
func mapView( _ mapView: MKMapView, didUpdate userLocation: MKUserLocation )
{
let regionRadius = 400 // in meters
let coordinateRegion = MKCoordinateRegionMakeWithDistance( userLocation.coordinate, regionRadius, regionRadius )
self.mapView.setRegion( coordinateRegion, animated: true)
}
}
The problem that occurs when you use the didUpdateUserLocation
method, you will not be able to scroll nor zoom to another location. It will keep pointing to your location.
The best way (that I've tried) is that you need to use the location manager.
In the viewDidLoad
add the following :
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLLocationAccuracyKilometer;;
// showing user location with the blue dot
[self.mapView setShowsUserLocation:YES];
self.mapView.delegate = self;
// getting user coordinates
CLLocation *location = [_locationManager location];
CLLocationCoordinate2D coordinate = [location coordinate];
// showing them in the mapView
_mapView.region = MKCoordinateRegionMakeWithDistance(coordinate, 250, 250);
[self.locationManager startUpdatingLocation];
this way you could display your location with the zoom that you want. I hope this will help.
Check out the method setUserTrackingMode of MKMapView. Probably the easiest way of tracking the user's location on a MKMapView is
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
That way you also don't need to be a MKMapViewDelegate. The possible modes are:
MKUserTrackingModeNone = 0, // the user's location is not followed
MKUserTrackingModeFollow, // the map follows the user's location
MKUserTrackingModeFollowWithHeading, // the map follows the user's location and heading
......
MKCoordinateRegion region =mapView.region;
region.center.latitude = currentLocation.latitude ;
region.center.longitude = currentLocation.longitude;
region.span.longitudeDelta /= 1000.0;
region.span.latitudeDelta /= 1000.0;
[mapView setRegion:region animated:YES];
[mapView regionThatFits:region];
Swift 3 version Use this method to zoom into any coordinate.
extension MKMapView{
func zoomIn(coordinate: CLLocationCoordinate2D, withLevel level:CLLocationDistance = 10000){
let camera =
MKMapCamera(lookingAtCenter: coordinate, fromEyeCoordinate: coordinate, eyeAltitude: level)
self.setCamera(camera, animated: true)
}
}
As suggested by Deepak, implement the mapView:didUpdate:
delegate method. Syntax for Swift 5:
func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
guard let newLocation = userLocation.location else { return }
let region = MKCoordinateRegion(center: newLocation.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2))
mapView.setRegion(region, animated: true)
}
Check the value of map.userLocation.coordinate
, the rest is OK.
精彩评论