MKMapView sometimes zoomz to user location sometimes zooms to middle of nowhere - ios

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.

Related

Problems with MKMapView on first use

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.

Find correct location in google map using latitude and longitude

Using latitude and longitude I want to display the correct position by annotation. My app is showing the area, but not the correct position by annotation.
Here is my code:
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mapView.delegate=self;
[self.mapView setShowsUserLocation:YES];
locatinmanager=[[CLLocationManager alloc]init];
[locatinmanager setDelegate:self];
[locatinmanager setDistanceFilter:kCLDistanceFilterNone];
[locatinmanager setDesiredAccuracy:kCLLocationAccuracyBest];
}
#pragma mark - MKMapViewDelegate methods.
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKCoordinateRegion region;
region.center.latitude=13.0839;
region.center.longitude=80.2700;
[mapView setRegion:region animated:YES];
}
You have set the region for your map but not the annotation.
For blue dot you need to add annotation for the same latitude and logitude.
Add following code with yours.
MapPoint *mp = [[MapPoint alloc] initWithCoordinate:**YouReagionsCordinat** title:#"**yourLocation**"];
[mapView addAnnotation:mp];
If still you are stucking then go through This tutorial
.

didUpdateUserLocation not calling with view reloaded

I'm getting an error in my IOS application. I've searched in the google and here, but the specific solution was not found!
I have a viewController called mapView that I use in two moments in my app, this view contains a MKMapView and the code.
In my mapView.h there is:
#property (strong, nonatomic) IBOutlet MKMapView *mapSpot;
And in my mapView.m there is:
- (void)viewDidLoad {
[super viewDidLoad];
[mapSpot setShowsUserLocation:YES];
}
- (void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([userLocation coordinate], 500, 500);
[mapSpot setRegion:region animated:YES];
}
So, in the first moment I load the mapView into other ViewController using:
#property (strong, nonatomic) ViewMap *mapView;
mapView = [[ViewMap alloc] initWithNibName:#"ViewMap" bundle:nil];
[self.view addSubview:[mapView view]];
I unload that ViewController and in another ViewController in other moment I load the MapView again, but in this moment the method: - (void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation not is called.
I verify if the first ViewController was unloaded and that was.
When I load the second ViewController there is a new instace of MapView, but not call the delegate method.
Anyone know something about that?
Thanks
==================================================================================
EDIT AND SOLVED:
the problem is in the way you are adding the view, in this line
[self.view addSubview:[mapView view]];
if you only add the view the controller code is not executed, instead of that you has to present the mapView, for example:
[self presentViewController:mapView animated:YES completion:nil];
The problem above, maybe happen because I'm using simulator to test app, and how the simulator not change the position map not get didUpdateUserLocation:
That's the unique explanation that I could have after the review the code, organize the classes read documentation and get error again.
Now, I'm using CLLocationManager to get position, after getting first time the position I stop it.
In the future I'll implement a system that track the user path, so using CLLocationManager is inevitable.
The mapView.m code after changes:
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *loc = [locations lastObject];
// store the location to use in any moment, it needs to be checked because the first time when get the coordinate not pass infos to load places according the current position
if (!location.latitude) {
location = [loc coordinate];
// set center the map at the current position
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location, 500, 500);
[mapSpotView setRegion:region animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"loadPlaces" object:nil];
[locationManager stopUpdatingLocation];
}
}
if someone has a better solution, please, post here!
That's it!

How to hide the blue dot and the circle on an MKMapView

Is there a easy way to hide it? I use the user location, but I don't want to show the blue dot. How can I hide it?
-- edit--
Am I using something wrong?
#interface ALMapaViewController : UIViewController <MKMapViewDelegate,
MKAnnotation>
{
IBOutlet MKMapView *mapaPrincipal;
id<ALMapaViewControllerDelegate> delegateMap;
CLLocationCoordinate2D coordinate;
}
my .m
#implementation ALMapaViewController
- (void)viewDidLoad{
[super viewDidLoad];
[mapaPrincipal setMapType:MKMapTypeStandard];
[mapaPrincipal setZoomEnabled:YES];
[mapaPrincipal setScrollEnabled:YES];
[mapaPrincipal.userLocation addObserver:self
forKeyPath:#"location"
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
context:nil];
[mapaPrincipal setShowsUserLocation:YES];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
MKCoordinateRegion region;
region.center = mapaPrincipal.userLocation.coordinate;
MKCoordinateSpan span;
span.latitudeDelta = 0.005f;
span.longitudeDelta = 0.005f;
region.span = span;
[mapaPrincipal setRegion:region animated:YES];
self.coordinate = region.center;
[mapaPrincipal addAnnotation:self];
[mapaPrincipal setShowsUserLocation:NO];
}
#end
I already used the showUserLocation and it still show the blue dots.
You want to receive user location updates but not show the blue dot.
One option is to use CLLocationManager to get updates instead of the map view's showsUserLocation. Call startUpdatingLocation on the location manager and implement its locationManager:didUpdateToLocation:fromLocation: delegate method.
If you don't want to use CLLocationManager, another option is to hide the user location view that is created by the map view by setting it's hidden property to YES in the map view's didAddAnnotationViews delegate method. The map view will continue to receive user location updates (because you are not setting showsUserLocation to NO) but the blue dot won't show because you're hiding its view.
An example of the second option is shown in this answer:
Hide MKUserLocation when MKMapView showsUserLocation == YES
An unrelated point is that you don't need to use key-value-observing to monitor changes to the map view's userLocation property. Use the mapView:didUpdateUserLocation: delegate method instead.
Very simple buddy
[mapView setShowUserLocation:NO];
You can hide the user location's view in the didAddAnnotationViews delegate method:
(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
MKAnnotationView *ulv = [mapView viewForAnnotation:mapView.userLocation];
ulv.hidden = YES;
}
check this https://stackoverflow.com/a/9713085/1344237
You can use this method
[mapViewSelf setShowsUserLocation:NO];
this works fine.
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews (NSArray<MKAnnotationView *> *)views {
MKAnnotationView *ulv = [mapView viewForAnnotation:mapView.userLocation];
if (ulv) {
CALayer *layer = [ulv valueForKeyPath:#"_accuracyLayer"];
if (layer) {
[layer removeFromSuperlayer];
}
}
}
The marked answer is correct, hiding it is very effective. Here's the delegate implemented code the accepted answer was referring to:
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
if let userView = views.first(where: { $0.annotation is MKUserLocation }) {
userView.isHidden = true
}
}

MKMapView Zooming In On User's Location Once But Not The Second Time in Tab-Bar App (iOS)

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];
}

Resources