If you pinch to zoom in/out in Apple’s Maps application while tracking the device’s location, the “pan” component of the pinch gesture is ignored and the blue location indicator remains fixed in the centre of the screen. This is not the case when using a plain MKMapView.
Assuming I already have the user’s location, how could I achieve this effect? I’ve tried resetting the centre coordinate in the delegate’s regionDid/WillChangeAnimated: methods but they’re only called at the start and end of the gesture. I also tried adding a UIPinchGestureRecognizer subclass that resets the centre coordinate when the touches move, but this resulted in rendering glitches.
Edit: For those who are interested, the following works for me.
// CenterGestureRecognizer.h
@interface CenterGestureRecognizer : UIPinchGestureRecognizer
- (id)initWithMapView:(MKMapView *)mapView;
@end
// CenterGestureRecognizer.m
@interface CenterGestureRecognizer ()
- (void)handlePinchGesture;
@property (nonatomic, assign) MKMapView *mapView;
@end
@implementation CenterGestureRecognizer
- (id)initWithMapView:(MKMapView *)mapView {
if (mapView == nil) {
[NSException raise:NSInvalidArgumentException format:@"mapView cannot be nil."];
}
if ((self = [super initWithTarget:self action:@selector(handlePinchGesture)])) {
self.mapView = mapView;
}
return self;
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
return NO;
}
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
return NO;
}
- (void)handlePinchGesture {
CLLocation *location = self.mapView.userLocation.location;
if (location != nil) {
[self.mapView setCenterCoordinate:location.coordinate];
}
}
@synthesize mapView;
@end
Then simply add it to your MKMapView:
[self.mapView addGestureRecognizer:[[[CenterGestureRecognizer alloc] initWithMapView:self.mapView] autorelease]];
When the user pinches the screen on the actual device (as opposed to the simulator), it causes both a pan and a pinch gesture – the pinch contains the “zoom” element of the motion, and the pan contains the vertical and horizontal change. You need to be intercepting and blocking the pan, and that means using a
UIPanGestureRecognizer.Set
scrollEnabledtoNO, then add aUIPanGestureRecognizerto reset the center coordinate. The combination will block both single-finger panning and the pan component of a pinch.Edit to add more details, and after seeing your code:
touchesMoved:withEventis called after the pan has already begun, so if you change the MKMapView’s center there, you’ll get the herky-jerky rendering problems you’ve described. What you really need is to create aUIPanGestureRecognizerwith a target-action, like so:…and then add a
didRecognizePanmethod to your controller, and do your center-resetting there.