Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird MKMapView behaviour when setting MKMapCamera in MKUserTrackingModeFollowWithHeading map mode

I noticed weird behaviour while working with MKMapView and MKMapCamera. I need to implement some of Apple Maps app's standard behaviour. Basically, what I need is to be able to switch between 2D and 3D mode when Map View's user tracking mode is set to MKUserTrackingModeFollowWithHeading.

Currently, my solution works fine when userTrackingMode is set to MKUserTrackingModeNone but it does weird animation in other modes(it happens regardless I setCamera: animated:YES or NO). When I log camera parameters just before and after setting new, the only difference is my change in pitch.

Another issue is changing camera's altitude to zoom in or out programatically. I'm trying to imitate zoom with pinch in or out gesture in IBAction method. In followWithHeadingMode map always returns to "default" zoom level(camera's altitude), whereas in other modes works great.

I started sample project to check what's going on, and that's my single view application's view controller with map view where problem occurs:

#import "CCViewController.h"

@interface CCViewController ()
@end

@implementation CCViewController

- (void)viewDidLoad{
    [super viewDidLoad];
}

- (void)setUpMap{
    [self.mapView setShowsUserLocation: YES];
}

- (void)viewDidAppear:(BOOL)animated{
    [self setUpMap];
}

- (IBAction)mapModeSwitchClicked:(id)sender {
    MKMapCamera *newCamera = [MKMapCamera camera];
    newCamera.centerCoordinate = self.mapView.camera.centerCoordinate;
    newCamera.heading = self.mapView.camera.heading;
    newCamera.altitude = self.mapView.camera.altitude;

    if(!self.mapView.camera.pitch){
        newCamera.pitch = 50;
        self.mapModeSwitch.title = @"2D";
    }
    else{
        newCamera.pitch = 0;
        self.mapModeSwitch.title = @"3D";
    }

    [self.mapView setCamera:newCamera animated:YES];
}

- (IBAction)locateMeButtonClicked:(id)sender {

        if(self.mapView.userTrackingMode != MKUserTrackingModeFollowWithHeading)
            [self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:YES];
        else
            [self.mapView setUserTrackingMode:MKUserTrackingModeNone animated:YES];
}

- (void)zoomMapWithZoomFactor:(double)factor{
    MKMapCamera *newCamera = [MKMapCamera camera];
    newCamera.pitch = self.mapView.camera.pitch;
    newCamera.heading = self.mapView.camera.heading;
    newCamera.altitude = self.mapView.camera.altitude * factor;
    newCamera.centerCoordinate = self.mapView.camera.centerCoordinate;

    [self.mapView setCamera:newCamera animated:YES];
}

- (IBAction)zoomInClicked:(id)sender {
    [self zoomMapWithZoomFactor: 0.5];
}

- (IBAction)zoomOutClicked:(id)sender {
     [self zoomMapWithZoomFactor: 2];
}


@end

What I'm looking for is behaviour similar to Apple Maps app. Do you have any ideas? What am I doing wrong ?

like image 415
krmt Avatar asked Oct 26 '13 12:10

krmt


2 Answers

I believe this is a bug in MapKit. I made similar observations with programmatic zooming while MKUserTrackingModeFollowWithHeading is enabled: The map shortly zooms out but returns to the previous zoom level as soon as it receives the next location update.

See rdar://15374402 (MapKit: programmatic zooming during UserTracking ) and rdar://15374604 (MKUserTrackingModeFollow prohibits annotation selection at the edge).

My advice: avoid MKUserTrackingModeFollow and MKUserTrackingModeFollowWithHeading as long as you want programmatic control over the displayed map region.

like image 94
Ortwin Gentz Avatar answered Nov 11 '22 13:11

Ortwin Gentz


iOS9 update:

It has the same effect: "altitude is zoomed out a bit"

but this effect is happening only when

[self.mapView setCamera:newCamera animated:NO];

not when using *animated:YES*

like image 24
Yaro Avatar answered Nov 11 '22 13:11

Yaro