I have a MapView and marked where the user's location and nearby there are other annotationView of various types regarding tourist attractions. I want the MapView is scrollable and zoomable to see all annotationView of the city, but when I move the MapView returns immediately centered shooting, ugly looking.
this is the code in MapViewController.m
- (void)viewDidLoad{
//.....
self.mapView.zoomEnabled=YES;
self.mapView.scrollEnabled = YES;
//......
}
- (void) locationManager:(CLLocationManager *) manager
didUpdateToLocation:(CLLocation *) newLocation
fromLocation:(CLLocation *) oldLocation {
//......
self.coordinate = CLLocationCoordinate2DMake(self.latitudine, self.longitudine);
CLLocationCoordinate2D min = CLLocationCoordinate2DMake(self.coordinate.latitude -0.005,
self.coordinate.longitude-0.005);
CLLocationCoordinate2D max = CLLocationCoordinate2DMake(self.coordinate.latitude+0.005,
self.coordinate.longitude+0.005);
CLLocationCoordinate2D center = CLLocationCoordinate2DMake((max.latitude + min.latitude)
/ 2.0, (max.longitude + min.longitude) / 2.0);
MKCoordinateSpan span = MKCoordinateSpanMake(max.latitude - min.latitude, max.longitude -
min.longitude);
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
self.mapView.region= region;
[mapView setRegion:region animated:TRUE];
//......
}
I think it is because the update is getting called constantly, so it will center the screen all the time with your mapview setregion bit.
When you declared your locationManager bet sure to set the sensitivity.
self.locationManager.distanceFilter = 10.0f;
This will only call the update if it changes more than 10 meters.
Everytime the device notices it has changed location, you are zooming the map to self.latitudine and self.longitudine. In the code you have shown you are not setting those values to anything new. Do you mean to be zooming in on the newLocation coordinates?
Related
I've got an issue. I'm using a MKMapView for displaying some annotations. I initialize a map view with default zoom. And it displays some map.
but when i try zooming, tiles not loaded, and map becomes empty. Like this.
I create my Map View via interface builder.
#property (nonatomic, weak) IBOutlet MKMapView* mapView;
What am I doing wrong? Is there any mandatory methods for implementation, that affect on this functional? And yes, there is an internet connection on my device.
Generally this can happens due to internet connection. If you have slow internet connection than it takes time to load map tiles.
About methods i recommended to override below method.
Override MKMapView delegate method -
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
Will call every time you zoom in/out and load map tiles.
PS - provide MKMapViewDelegate to your view controller.
I had the same loading problem till I got the problem working by googling!
Note: Effective ios 8 & later, we need to add a value NSLocationWhenInUseUsageDescription in Info.plist file with our own value as description. This is because showsUserLocation property of **MKMapView** doesn't work straight away. More info here !!!!
//This should be declared in .h file
#property(nonatomic, strong) CLLocationManager *locationManager;
- (void)viewDidLoad {
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
self.locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER) {
[self.locationManager requestWhenInUseAuthorization];
}
#endif
[self.locationManager startUpdatingLocation];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
self.mapView.showsUserLocation = YES;
}
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region;
region.center = self.locationView.userLocation.coordinate;
MKCoordinateSpan span;
span.latitudeDelta = 0.015; ->Adjust this value to zoom as per your requirement
span.longitudeDelta = 0.015;
region.span = span;
[self.mapView setRegion:region animated:YES];
}
I firmly believe this will yield the expected result without fail, i.e. MKMapView zoom to the current user location.
I am using am mapview and sometimes my map will zoom onto my users location when I open it but sometimes it will zoom to the middle of an ocean. I don't know what is causing this, this is the code I am using for zooming. I don't want the map to track the user but just zoom to their location once they open the map
-(void) viewDidAppear:(BOOL)animated{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 600.0f, 600.0f);
[self.mapView setRegion:region animated:YES];
}
-(void) viewDidLoad{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView setShowsUserLocation:YES];
}
I encountered this issue before. It seems that mapView is slow to load and detect user location sometimes, resulting in your code in viewDidAppear being executed before the map view can check user's location. Thus, the spot in the ocean.
It will be better to use mapView's delegate to display user location when it's ready:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if(isShowUserLocation)
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 600.0, 600.0);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
isShowUserLocation = NO;
}
}
Set isShowUserLocation = YES in viewDidLoad. This ensures the user location is shown once on entry and also selectively when you need it.
Edit 1:
#implementation MapViewController
{
BOOL isShowUserLocation;
}
-(void) viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
[self.mapView setShowsUserLocation:YES];
isShowUserLocation = YES;
}
Edit 2:
Alternatively, use CLLocationManager - see this post. It allows you stop the updating. Do include CoreLocation.framework. You may need to handle some nitty-gritty issues when interacting CLLocationManager with MapView though.
When you pass 0's for lat and long, you will git a spot in the middle of the ocean south of Ghana in Africa.
I have an MKMapView but when the user logs on the first time and allows location services, it doesn't show there location. If they leave the view and come back, it works. I am using what is listed bellow to solve the problem. It solves the problem but then the user can no longer zoom because when there location is updated, it takes them back to the specified location. How would I fix the first problem while making scrolling work.
Here is what I am using:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
MKUserLocation *myLocation = [self.schoolMap userLocation];
CLLocationCoordinate2D coord = [[myLocation location] coordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 9000, 9000);
[self.schoolMap setRegion:region animated:NO];
}
Do not use location manager at all. Just tell the map view to track the user's location. Then implement this delegate method:
- (void)mapView:(MKMapView *)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation {
CLLocationCoordinate2D coordinate = userLocation.location.coordinate;
MKCoordinateRegion reg =
MKCoordinateRegionMakeWithDistance(coordinate, 600, 600);
mapView.region = reg;
}
Now, that will keep trying to set the map every time the user moves, so if you don't want that, add a BOOL switch so that you only do this the first time (when the map first gets the user location).
It is possible that you did not received user's location by the time you set the region. There's a way to handle this situation by letting the mapView shows the user's location whenever it got to as follows:
CLLocation *location = [[self.schoolMap userLocation] location];
bool hasLocation = location!=nil;
if (!hasLocation) {
[self.mapView showsUserLocation];
} else {
CLLocationCoordinate2D zoomLocation = location.coordinate;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 2000, 2000);
[self.mapView setRegion:viewRegion animated:NO];
Note that this does not demand you update the location on a regular basis.
I init my mapviewControler like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstShow=TRUE;
self.mapView.delegate=self;
self.mapView.showsUserLocation=YES;
self.cllmng=[[CLLocationManager alloc]init];
self.cllmng.delegate=self;
self.cllmng.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
self.cllmng.distanceFilter=50;
[self.cllmng startUpdatingLocation];
}
and I make mapviewControler implement CLLocationManagerDelegate, and implement - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations in my code.
The problem I have is that I want to init map view centred on current user location with a proper scale. I intend to do this by
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation * currentLoci=[locations lastObject];
MKCoordinateRegion r;
MKCoordinateSpan span;
span.latitudeDelta = 1;
span.longitudeDelta = 1;
r.span = span;
CLLocationCoordinate2D c;
c.longitude=currentLoci.coordinate.longitude;
c.latitude=currentLoci.coordinate.latitude;
r.center = c;
[self.mapView setRegion:r animated:YES];
}
But sometimes, after [self.cllmng startUpdatingLocation] called in the -(void) viewDidload, I cannot get a call of - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations immediately. Thus, the map view just init showing user location but showing the whole Australia. How can I set the scale/span in the init of map view even didUpdateLocations is not triggered? THX!
INstead of modifying the region yourself using a CLLocation manager you could just set the trackingMode of the mapView and it'll center and zoom in on your position automatically. It will be possible for the user to disable the tracking mode if they start dragging the map around, but you can disable user interaction if you really want them to have no control. Here is how to do it
[self.mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
ref: https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html#//apple_ref/occ/instm/MKMapView/setUserTrackingMode:animated:
iOS 11.x Swift 4.0 Craigs answer, updated.
mapView.showsUserLocation = true
Not so obvious I fear.
I have an MKMapView as part of a Navigation Controller in a Tab Bar based app.
I click a UIButton on the first View Controller and it pushes to the second View Controller which contains the MKMapView. When the Map View loads, it zooms in on the user's location using:
- (void)mapView:(MKMapView *)theMapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if ( !initialLocation )
{
self.initialLocation = userLocation.location;
MKCoordinateRegion region;
region.center = theMapView.userLocation.coordinate;
region.span = MKCoordinateSpanMake(2.0, 2.0);
region = [theMapView regionThatFits:region];
[theMapView setRegion:region animated:YES];
}
}
When I hit the back button on the Navigation Controller above the MapView and then click back to the map, it no longer zooms in on the user's current location, but just has the full zoom out default:
Here's a picture of the view the second time.
I figure it would work correctly if I could somehow call the didUpdateUserLocation in the viewDidAppear method but I'm not sure how to pull this off since the didUpdateUserLocation is a delegate method.
Is that the right approach or is there a different approach I should take to do this? Thanks!
P.S. I've seen this question but it's slightly different with it's use of a modal view controller
I would pull all of the zooming code into its own method that can be messaged from -viewDidAppear: and -mapView:didUpdateToUserLocation:.
- (void)zoomToUserLocation:(MKUserLocation *)userLocation
{
if (!userLocation)
return;
MKCoordinateRegion region;
region.center = userLocation.location.coordinate;
region.span = MKCoordinateSpanMake(2.0, 2.0); //Zoom distance
region = [self.mapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
}
Then in -viewDidAppear:...
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self zoomToUserLocation:self.mapView.userLocation];
}
And in the -mapView:didUpdateToUserLocation: delegate method...
- (void)mapView:(MKMapView *)theMapView didUpdateToUserLocation:(MKUserLocation *)location
{
[self zoomToUserLocation:location];
}