MKMapKit iOS 5. Can I set a desired delegate when I want? - ios

I have a question about map and delegate. I am doing a exercise from a book and it says to me to use the method
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//CLLocationCoordinate2D loc = [userLocation coordinate];
self.coord2D = [userLocation coordinate];
//MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coord2D, 250, 250);
[worldView setRegion:region animated:YES];
}
Which means every time I move my phone from my location it will show myself on screen. I also create a button that calls this method. Therefore if I am scrolling my map I can see where I am.
The problem is: if I am in a car and want to scroll my map it will become a difficult task due this method will be call all the time I change my location.
Is there any other method or if I have an option to activate and deactivate a delegate?
Thanks in advance.

As far as I can tell it's quite simple. Just have a button for activating and deactivating it.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
//CLLocationCoordinate2D loc = [userLocation coordinate];
self.coord2D = [userLocation coordinate];
if (self.trackUserLocation) {
//MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coord2D, 250, 250);
[worldView setRegion:region animated:YES];
}
}
The property:
#property (nonatomic, assign) BOOL trackUserLocation;
The button action:
self.trackUserLocation = !self.trackUserLocation;
You don't have to make it any harder than that.

Related

MKMapView frozen after setting region

I have a MKMapView and want to limit the zoom-out-level.
My approach is the following using the regionWillChangeAnimated-Method:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
//Maximum zoom-out-level
MKCoordinateSpan maxSpan;
maxSpan.latitudeDelta = 0.2;
maxSpan.longitudeDelta = 0.2;
if (self.mapView.region.span.latitudeDelta > maxSpan.latitudeDelta ) {
CLLocation *location = [self.locationManager location];
CLLocationCoordinate2D coordinate = [location coordinate];
MKCoordinateRegion region;
region.center = coordinate;
region.span = maxSpan;
[self.mapView setRegion:region animated:YES];
}
}
When I zoom out of the maximum span, the map-region is reset correctly to the maximum.
Unfortunately, after I call setRegion:, the mapView freezes and I can't zoom or interact anymore with the mapView. The app doesn't crash though.
Does anyone know what's wrong in my code? Is there maybe a better way to limit the zoom-out-level?
Thanks a lot in advance!

viewForAnnotation didn't moves the userLocation

I've implemented - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { method to change the default location of userLocation Annotation. Inside this method I've used:
if (annotation==(mapView.userLocation)) {
MKAnnotationView *myAnotation = [[MKAnnotationView alloc] init];
myAnotation.image = self.userPointImage.image;
myAnotation.centerOffset = CGPointMake(0, 250);
return myAnotation;
}
else
{
return nil;
}
Which successfully moves the default userLocation annotation to center bottom. But as I'm also using heading so when move my phone it is still rotating the map from center.
- (void)locationManager:(CLLocationManager *) manager didUpdateHeading:(CLHeading *) newHeading {
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:true];
}
But the userLocation annotation is below. So how to do that?
UPDATE I found this question and tried applying it. But as I'm using heading so it crashes the app.
In my didUpdateUserLocation method I added [self moveCenterByOffset:CGPointMake(0, 200) from:userLocation.coordinate]; and this method is as follows:
- (CLLocationCoordinate2D)moveCenterByOffset:(CGPoint)offset from:(CLLocationCoordinate2D)coordinate
{
CGPoint point = [self.mapView convertCoordinate:coordinate toPointToView:self.mapView];
point.x += offset.x;
point.y += offset.y;
CLLocationCoordinate2D center = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
return center;
}
and then in my didUpdateUserLocation method I updated it as: MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([self moveCenterByOffset:CGPointMake(0, -250) from:userLocation.coordinate], 800.0f, 200.0f); and [mapView setRegion:region animated:NO]; as I'm using heading so animation is set to NO. But now as I run the code it starts jerking between center and the new point.
MKCoordinateRegion region = mapClinicsView.region;
set 'region.center'
It will helps you to navigate your map center position
make sure 'region.center' and annotation center latitute and longitute is same

Within a UICollectionViewCell, setRegion has no effect for a MKMapView

I have set up a simple MKMapView (it is intended just to display a location on the map and nothing more) within one cell of a section of a CollectionView and am unable to set its region using setRegion. The MKMapViewDelegate is correctly set to the UICollectionViewCell as shown by breakpoints being hit within all the delegate methods.
I first tried to set the region in the View Controller's cellForItemAtIndexPath but I'm guessing this is too early, i.e. before the map is loaded so nothing happens and it loads a default location in the middle of the ocean.
I have tried passing the CLCoordinateLocation2D from the view controller to a CLCoordinateLocation2D in the cell during cellForItemAtIndexPath to set the region within the cell but where is the appropriate place to set the region? In a ViewController it should be done in ViewDidAppear rather than ViewDidLoad or ViewWillAppear so that the map is loaded but I cannot find an equivalent event for a collectionviewcell. awakeFromNib is clearly too soon. I have tried using various mapView delegates such as:
- (void)mapView:(MKMapView *)mapView1
regionWillChangeAnimated:(BOOL)animated
{
MKCoordinateSpan span = {.latitudeDelta = 0.0025, .longitudeDelta = 0.0025};
MKCoordinateRegion adjustedRegion = [mapView1 regionThatFits:MKCoordinateRegionMakeWithDistance(coords, 200, 200)];
[mapView1 setRegion:adjustedRegion animated:YES];
}
which runs but again does not change the region. I have tried
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView and
- (void)mapViewWillStartRenderingMap:(MKMapView *)mapView
which seemed the best bets but a breakpoint before and after the setRegion line shows the region is never updated to the region I'm setting it to. The events all should be at a time that the map is fully loaded so why does setRegion simply have no effect??
Cell h file:
#interface BasicsCollectionViewCell : UICollectionViewCell
#property (strong, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic) CLLocationCoordinate2D coords;
#end
Cell m file:
#interface BasicsCollectionViewCell() <MKMapViewDelegate>
#end
#implementation BasicsCollectionViewCell
#synthesize mapView;
#synthesize coords;
- (void)mapView:(MKMapView *)mapView1
regionWillChangeAnimated:(BOOL)animated
{
MKCoordinateSpan span = {.latitudeDelta = 0.0025, .longitudeDelta = 0.0025};
MKCoordinateRegion adjustedRegion = [mapView1 regionThatFits:MKCoordinateRegionMakeWithDistance(coords, 200, 200)];
[mapView1 setRegion:adjustedRegion animated:YES];
}
And the relevant part of cellForItemAtIndexPath:
cell0 = (BasicsCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"BasicsCell" forIndexPath:indexPath];
CLLocationCoordinate2D coord = {.latitude = self.latitude, .longitude = self.longitude};
[cell0 setCoords:coord];
cell0.mapView.delegate = cell0;
MKCoordinateSpan span = {.latitudeDelta = 0.0025, .longitudeDelta = 0.0025};
MKCoordinateRegion adjustedRegion = [cell0.mapView regionThatFits:MKCoordinateRegionMakeWithDistance(coord, 200, 200)];
[cell0.mapView setRegion:adjustedRegion animated:YES];
return cell0;
EDIT:
If I put breakpoints in the following code before and after the setRegion line at the asterixed points...
- (void)mapViewWillStartRenderingMap:(MKMapView *)mapView
{
MKCoordinateSpan span = {.latitudeDelta = 0.0025, .longitudeDelta = 0.0025};
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:MKCoordinateRegionMakeWithDistance(coords, 200, 200)];
*****[mapView setRegion:adjustedRegion animated:YES];
*****}
then the debugger gives the following at the first breakpoint:
po self.mapView.region
{
(latitude = -41.508575000000008, longitude = 174.19921900000011)
(latitudeDelta = 13.733789001832008, longitudeDelta = 59.305518116231042)
}
And the same at the breakpoint immediately after:
po self.mapView.region
{
(latitude = -41.508575000000008, longitude = 174.19921900000011)
(latitudeDelta = 13.733789001832008, longitudeDelta = 59.305518116231042)
}
While at both breakpoints, the following is the (correct) value of adjustedRegion:
po adjustedRegion
{
(latitude = -0.13506928037132482, longitude = 51.518398284912109)
(latitudeDelta = 0.0018087389042361623, longitudeDelta = 0.0058458603824931288)
}
So it is simply that either setRegion is being ignored for some reason or it’s overridden by something else. Any ideas which?
I have faced similar one, where map region was not changed. So I manually called mapView delegate method
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
in - (void) viewDidAppear:(BOOL)animated of view controller.
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Manually called delegate method to forcefully set region.
[self mapView:self.mapView regionDidChangeAnimated:YES];
}
In your case call this method right after when you set map region. From your above code for example in cellForItemAtIndexPath method. For example:
cell0 = (BasicsCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"BasicsCell" forIndexPath:indexPath];
CLLocationCoordinate2D coord = {.latitude = self.latitude, .longitude = self.longitude};
[cell0 setCoords:coord];
cell0.mapView.delegate = cell0;
MKCoordinateSpan span = {.latitudeDelta = 0.0025, .longitudeDelta = 0.0025};
MKCoordinateRegion adjustedRegion = [cell0.mapView regionThatFits:MKCoordinateRegionMakeWithDistance(coord, 200, 200)];
[cell0.mapView setRegion:adjustedRegion animated:YES];
[cell0.mapView setRegion:adjustedRegion animated:YES];
// Force call of delegate method
[self mapView:cell0.mapView regionDidChangeAnimated:YES];
return cell0;
Note:
Don't forgot to override regionDidChangeAnimated method in view controller.
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
}

Translate MapKit Region Button Action to Method

Apologies in advance for what must surely be so simple.
I want my map to zoom to a programmatically defined region surrounding the user's location. I've found tons of code where this is done via a button action, but I need it done automatically when the map loads. I'll post what I've tried here. Probably missing something very obvious. The meat of these both work as button actions, so I assume my issue is with my method code (first line of each).
Method 1: Using MKCoordinateSpanMake
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
float spanX = 0.00725;
float spanY = 0.00725;
MKCoordinateRegion region;
region.center.latitude = self.mapView.userLocation.coordinate.latitude;
region.center.longitude = self.mapView.userLocation.coordinate.longitude;
region.span = MKCoordinateSpanMake(spanX, spanY);
[self.mapView setRegion:region animated:YES];
}
Method 2: Using MKCoordinateRegionMakeWithDistance
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKUserLocation *userLocation = _mapView.userLocation;
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance (
userLocation.location.coordinate, 3000, 3000);
[_mapView setRegion:region animated:YES];
}
As always, thanks so much for your time and advice.
Move to viewDidLoad:
- (void)viewDidLoad
{
MKUserLocation *userLocation = _mapView.userLocation;
MKCoordinateRegion region =[_mapView regionThatFits:MKCoordinateRegionMakeWithDistance (userLocation.location.coordinate, 3000, 3000)];
[_mapView setRegion:region animated:YES];
}
Hope that will help.

How to set zoom level to user location in MapView

Im using MKMapView to get the users location and when the view loads it shows the whole world view. Is there anyway that I can set a zoom level so that the users don't have to keep zooming in always to get the city view or street view...It would be a great help. I've posted my code below for reference...
- (void)viewDidLoad
{
[super viewDidLoad];
[ self.mapView.delegate self];
[self.mapView setShowsUserLocation:YES];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationCoordinate2D loc = [userLocation coordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 500, 500);
[self.mapView setRegion:region animated:YES];
}
- (void)viewDidUnload {
[super viewDidUnload];
[_mapView setShowsUserLocation:NO];
}
The code you've posted should work for the most part except for this critical line in viewDidLoad:
[ self.mapView.delegate self];
Essentially, this line does nothing.
It is not setting the map view's delegate property (which is what I assume it is supposed to do).
What it is actually doing is calling self on the delegate property.
The map view's delegate is not getting set (it stays nil) and so the didUpdateUserLocation delegate method never gets called and so the map is not zooming to the user's location.
The line should be this:
[self.mapView setDelegate:self];
or even simpler:
self.mapView.delegate = self;
Note that in iOS 5 or later, you can just set userTrackingMode and the map view will automatically zoom to and follow the user's location so you don't have to do it manually.
Also note that since iOS 6, viewDidUnload is deprecated and is not even called by the OS. You probably want to move the disabling of showsUserLocation to viewWillDisappear (and move the enabling to viewWillAppear).
Try this May be Help full for you
MKCoordinateRegion startupRegion;
startupRegion.center = CLLocationCoordinate2DMake(26.0000, 75.00);
startupRegion.span = MKCoordinateSpanMake(0.5, 0.597129);
[mapViewObj setRegion:startupRegion animated:YES];
here 26.0000 and 75.00 is user location and MKCoordinateSpanMake is zoom level. It's increasing your zoom as you wish.
Try this, In ViewDidLoad
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = 39.281516; // your latitude value
zoomLocation.longitude= -76.580806; // your longitude value
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta=0.18; // change as per your zoom level
span.longitudeDelta=0.18;
region.span=span;
region.center= zoomLocation;
[self.mapView setRegion:region animated:TRUE];
[self.mapView regionThatFits:region];
set MKCoordinateRegion and change region span according to your requirement
MKCoordinateRegion region;
CLLocation* currentLocation = (CLLocation*)from ; // current location
if(currentLocation.coordinate.latitude > maxLat)
maxLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.latitude < minLat)
minLat = currentLocation.coordinate.latitude;
if(currentLocation.coordinate.longitude > maxLon)
maxLon = currentLocation.coordinate.longitude;
if(currentLocation.coordinate.longitude < minLon)
minLon = currentLocation.coordinate.longitude;
region.center.latitude = (maxLat + minLat) / 2;
region.center.longitude = (maxLon + minLon) / 2;
region.span.latitudeDelta = 0.4; // change as per required zoom level
region.span.longitudeDelta = 0.4; // change as per required zoom level
// input that region and set map area as below 30000
_mapView.region =MKCoordinateRegionMakeWithDistance(currentLocation.coordinate,30000, 30000);
[_mapView setRegion:region animated:YES];
[_mapView regionThatFits:region];
[_mapView reloadInputViews];
// center your map at Current location
_mapView.centerCoordinate = _mapView.userLocation.location.coordinate;
// To get current location use CLLocationManagerDelegate
#interface GetCurrentLocation : NSObject<CLLocationManagerDelegate>
#property(nonatomic,strong)CLLocationManager *_locationManager;
-(void)getLocation;
#end
-(void)getLocation{
_locationManager = [[CLLocationManager alloc] init];
[_locationManager setDelegate:self];
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
_locationManager.distanceFilter = kCLDistanceFilterNone;
[_locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation// you can get current location here
{
CLLocationCoordinate2D coord;
coord.latitude = newLocation.coordinate.latitude;
coord.longitude = newLocation.coordinate.longitude;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
// NSLog(#"locationManager:%# didFailWithError:%#", manager, error);
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = 0.3;
mapRegion.span.longitudeDelta = 0.3;
[mapView setRegion:mapRegion animated: YES];
}

Resources