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.
Related
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 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 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?
So I am building a location based game and have a problem getting a users location to initialize properly.
It doesn't always happen, but sometimes the location never changes from 0,0.
This causes a problem as I have a loading view (vault) that blocks the map from being displayed until the player's location is loaded and not 0,0. So if the user location doesnt get set, the vault never opens showing the map.
Is there any other way to ensure the user location is loaded?
FYI - I already ensure they have location services enabled and their device is capable.
I am having this issue on and off on my own devices with everything enabled properly.
ViewDidLoad:
/*Location Manager*/
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager setDistanceFilter:100.0];//Update location to network when player moves X meters
[locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];//Nearest 1000 meters (.33 miles)
[locationManager startUpdatingLocation];
/*Map View*/
mapLoaded = false;
currentFilter = 0;
[_mapView setDelegate:self];
[_mapView setShowsUserLocation:YES];
[_mapView setMapType:MKMapTypeSatellite];
Location Manager Delegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//Wait until User Location is initialized (NOT 0,0)
NSLog(#"Latitude: %f, Longitude: %f",_mapView.userLocation.coordinate.latitude,_mapView.userLocation.coordinate.longitude);
if(_mapView.userLocation.location.coordinate.latitude!=0.00 && _mapView.userLocation.location.coordinate.longitude!=0.00){
//Update Player Object
[player setLatitude:_mapView.userLocation.location.coordinate.latitude];
[player setLongitude:_mapView.userLocation.location.coordinate.longitude];
[player updatePlayerLocation];//Update location to network
if(mapLoaded){//Map already loaded, call refresh
[self refreshMap];
}
else{//First load of map
[_mapView setCenterCoordinate:_mapView.userLocation.location.coordinate];
[self populateMap];
[self openVault];
mapLoaded = true;//Disable map first load
//timerMap = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(refreshMap) userInfo:nil repeats:YES];//Auto-Refresh of Map
}
}
}
You seem to be trying to get the location from the _mapView.userLocation CLLocation object.
You should rather use the last item in the locations array passed into your method.
see also documentation, guide with snippets
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];
}