From 41d28e7203ab9545fcaaedeeb5836837a865b364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sat, 18 Apr 2015 19:47:52 -0700 Subject: [PATCH] Added drift-zooming effect after pinch gesture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply a subtle animated zoom after a pinch gesture completes. Lots of magic numbers involved. Avoid drifting when the pinch is near-static, and when the scale factor would go below the minimum. There is more resistance to pinching outward than pinching inward, because it’s far easier to lose your place when you accidentally zoom out. Disabled two-finger pan, which is typically reserved for changing pitch; otherwise, it’s easy to accidentally pan while intending to pinch. --- platform/ios/MGLMapView.mm | 54 ++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 0586f17ae..6c5f3cc2e 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -327,6 +327,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // _pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; _pan.delegate = self; + _pan.maximumNumberOfTouches = 1; [self addGestureRecognizer:_pan]; _scrollEnabled = YES; @@ -747,17 +748,60 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; if (log2(newScale) < mbglMap->getMinZoom()) return; - double scale = mbglMap->getScale(); - - mbglMap->scaleBy(newScale / scale, [pinch locationInView:pinch.view].x, [pinch locationInView:pinch.view].y); + mbglMap->setScale(newScale, [pinch locationInView:pinch.view].x, [pinch locationInView:pinch.view].y); } else if (pinch.state == UIGestureRecognizerStateEnded || pinch.state == UIGestureRecognizerStateCancelled) { + CGFloat velocity = pinch.velocity; + if (velocity > -0.5 && velocity < 3) + { + velocity = 0; + } + CGFloat duration = velocity > 0 ? 1 : 0.25; + + CGFloat scale = self.scale * pinch.scale; + CGFloat newScale = scale; + if (velocity >= 0) + { + newScale += scale * velocity * duration * 0.1; + } + else + { + newScale += scale / (velocity * duration) * 0.1; + } + + if (newScale <= 0 || log2(newScale) < mbglMap->getMinZoom()) + { + velocity = 0; + } + + if (velocity) + { + CGPoint pinchCenter = [pinch locationInView:pinch.view]; + mbglMap->setScale(newScale, pinchCenter.x, pinchCenter.y, secondsAsDuration(duration)); + } + mbglMap->setGestureInProgress(false); - + [self unrotateIfNeededAnimated:YES]; + + if (velocity) + { + self.animatingGesture = YES; - [self notifyMapChange:@(mbgl::MapChangeRegionDidChange)]; + __weak MGLMapView *weakSelf = self; + + [self animateWithDelay:duration animations:^ + { + weakSelf.animatingGesture = NO; + + [weakSelf notifyMapChange:@(mbgl::MapChangeRegionDidChangeAnimated)]; + }]; + } + else + { + [self notifyMapChange:@(mbgl::MapChangeRegionDidChange)]; + } } }