diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 63d799bda97..09142c40936 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -762,6 +762,25 @@ IB_DESIGNABLE */ - (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets; +/** + Returns the point in this view's coordinate system on which to "anchor" in + response to a user-initiated gesture. + + For example, a pinch-to-zoom gesture would anchor the map at the midpoint of + the pinch. + + If the `userTrackingMode` property is not `MGLUserTrackingModeNone`, the + user annotation is used as the anchor point. + + Subclasses may override this method to provide specialized behavior - for + example, anchoring on the map's center point to provide a "locked" zooming + mode. + + @param gesture An anchorable user gesture. + @return The point on which to anchor in response to the gesture. + */ +- (CGPoint)anchorPointForGesture:(UIGestureRecognizer *)gesture; + /** The distance from the edges of the map view’s frame to the edges of the map view’s logical viewport. diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 5d1bcb11092..4e304b23a55 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -1235,11 +1235,7 @@ - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch _mbglMap->cancelTransitions(); - CGPoint centerPoint = [pinch locationInView:pinch.view]; - if (self.userTrackingMode != MGLUserTrackingModeNone) - { - centerPoint = self.userLocationAnnotationViewCenter; - } + CGPoint centerPoint = [self anchorPointForGesture:pinch]; if (pinch.state == UIGestureRecognizerStateBegan) { @@ -1311,7 +1307,7 @@ - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch [self unrotateIfNeededForGesture]; } - _previousPinchCenterCoordinate = [self convertPoint:[pinch locationInView:pinch.view] toCoordinateFromView:self]; + _previousPinchCenterCoordinate = [self convertPoint:centerPoint toCoordinateFromView:self]; _previousPinchNumberOfTouches = pinch.numberOfTouches; } @@ -1321,11 +1317,7 @@ - (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate _mbglMap->cancelTransitions(); - CGPoint centerPoint = [rotate locationInView:rotate.view]; - if (self.userTrackingMode != MGLUserTrackingModeNone) - { - centerPoint = self.userLocationAnnotationViewCenter; - } + CGPoint centerPoint = [self anchorPointForGesture:rotate]; if (rotate.state == UIGestureRecognizerStateBegan) { @@ -1454,11 +1446,7 @@ - (void)handleDoubleTapGesture:(UITapGestureRecognizer *)doubleTap if (doubleTap.state == UIGestureRecognizerStateEnded) { [self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap]; - CGPoint gesturePoint = [doubleTap locationInView:doubleTap.view]; - if (self.userTrackingMode != MGLUserTrackingModeNone) - { - gesturePoint = self.userLocationAnnotationViewCenter; - } + CGPoint gesturePoint = [self anchorPointForGesture:doubleTap]; mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y); _mbglMap->scaleBy(2, center, MGLDurationInSeconds(MGLAnimationDuration)); @@ -1486,11 +1474,7 @@ - (void)handleTwoFingerTapGesture:(UITapGestureRecognizer *)twoFingerTap } else if (twoFingerTap.state == UIGestureRecognizerStateEnded) { - CGPoint gesturePoint = [twoFingerTap locationInView:twoFingerTap.view]; - if (self.userTrackingMode != MGLUserTrackingModeNone) - { - gesturePoint = self.userLocationAnnotationViewCenter; - } + CGPoint gesturePoint = [self anchorPointForGesture:twoFingerTap]; mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y); _mbglMap->scaleBy(0.5, center, MGLDurationInSeconds(MGLAnimationDuration)); @@ -1528,11 +1512,8 @@ - (void)handleQuickZoomGesture:(UILongPressGestureRecognizer *)quickZoom if (newZoom < _mbglMap->getMinZoom()) return; - CGPoint centerPoint = self.contentCenter; - if (self.userTrackingMode != MGLUserTrackingModeNone) - { - centerPoint = self.userLocationAnnotationViewCenter; - } + CGPoint centerPoint = [self anchorPointForGesture:quickZoom]; + _mbglMap->scaleBy(powf(2, newZoom) / _mbglMap->getScale(), mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); @@ -1564,11 +1545,8 @@ - (void)handleTwoFingerDragGesture:(UIPanGestureRecognizer *)twoFingerDrag CGFloat pitchNew = currentPitch - (gestureDistance / slowdown); - CGPoint centerPoint = self.contentCenter; - if (self.userTrackingMode != MGLUserTrackingModeNone) - { - centerPoint = self.userLocationAnnotationViewCenter; - } + CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag]; + _mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); [self notifyMapChange:mbgl::MapChangeRegionIsChanging]; @@ -1578,7 +1556,21 @@ - (void)handleTwoFingerDragGesture:(UIPanGestureRecognizer *)twoFingerDrag [self notifyGestureDidEndWithDrift:NO]; [self unrotateIfNeededForGesture]; } +} +- (CGPoint)anchorPointForGesture:(UIGestureRecognizer *)gesture { + if (self.userTrackingMode != MGLUserTrackingModeNone) + { + return self.userLocationAnnotationViewCenter; + } + + // Special case for two-finger drag and quickzoom + if ([gesture isKindOfClass:[UIPanGestureRecognizer class]] || [gesture isKindOfClass:[UILongPressGestureRecognizer class]]) + { + return self.contentCenter; + } + + return [gesture locationInView:gesture.view]; } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer