From a19e6b73a22a2e1802dc60200651f769631ef1e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Sun, 5 Jun 2016 13:29:23 -0700 Subject: [PATCH] [ios] Made annotation view position animatable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don’t normally want an annotation view to animate its position, because that makes the view appear to lag behind the map. But when the annotation view moves due to the underlying annotation model object moving, the developer may want exactly that effect. This change continues to disable the default implicit bounds (and now position) animation. It also groups the view updates in -updateAnnotationViews in a transaction that disables animation actions, to improve perceived performance with a large number of annotations. However, when the annotation model object changes, we move the annotation view outside of that transaction to allow the developer to opt into animation. If the developer moreover wants the annotation view to animate even due to the viewport changing, they can override -setCenter: to use a UIView animation block. Fixes #5230. --- platform/ios/app/MBXAnnotationView.m | 12 ++++++++++++ platform/ios/src/MGLAnnotationView.mm | 2 +- platform/ios/src/MGLMapView.mm | 14 +++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/platform/ios/app/MBXAnnotationView.m b/platform/ios/app/MBXAnnotationView.m index 890881a3162..6925358a30c 100644 --- a/platform/ios/app/MBXAnnotationView.m +++ b/platform/ios/app/MBXAnnotationView.m @@ -25,4 +25,16 @@ - (void)setCenterColor:(UIColor *)centerColor { } } +- (nullable id)actionForLayer:(CALayer *)layer forKey:(NSString *)event +{ + if ([event isEqualToString:@"position"]) + { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:event]; + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + animation.speed = 0.1; + return animation; + } + return [super actionForLayer:layer forKey:event]; +} + @end diff --git a/platform/ios/src/MGLAnnotationView.mm b/platform/ios/src/MGLAnnotationView.mm index 4f16eb32586..a63114273bd 100644 --- a/platform/ios/src/MGLAnnotationView.mm +++ b/platform/ios/src/MGLAnnotationView.mm @@ -98,7 +98,7 @@ - (void)updateScaleForPitch:(CGFloat)pitch - (id)actionForLayer:(CALayer *)layer forKey:(NSString *)event { // Allow mbgl to drive animation of this view’s bounds. - if ([event isEqualToString:@"bounds"]) + if ([event isEqualToString:@"bounds"] || [event isEqualToString:@"position"]) { return [NSNull null]; } diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index cde877407ba..a677aacca71 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -1774,12 +1774,19 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); NSString *symbolName; - if (!annotationContext.annotationView) + if (annotationContext.annotationView) + { + // Redundantly move the associated annotation view outside the scope of the animation-less transaction block in -updateAnnotationViews. + CGPoint center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self]; + [annotationContext.annotationView setCenter:center pitch:self.camera.pitch]; + } + else { MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; symbolName = annotationImage.styleIconIdentifier; } + // Update the annotation’s backing geometry to match the annotation model object. Any associated annotation view is also moved by side effect. However, -updateAnnotationViews disables the view’s animation actions, because it can’t distinguish between moves due to the viewport changing and moves due to the annotation’s coordinate changing. _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, symbolName.UTF8String ?: "" }); if (annotationTag == _selectedAnnotationTag) { @@ -4470,6 +4477,9 @@ - (void)updateAnnotationViews return; } + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + for (auto &pair : _annotationContextsByAnnotationTag) { CGRect viewPort = CGRectInset(self.bounds, -_largestAnnotationViewSize.width - MGLAnnotationUpdateViewportOutset.width, -_largestAnnotationViewSize.height - MGLAnnotationUpdateViewportOutset.width); @@ -4506,6 +4516,8 @@ - (void)updateAnnotationViews [annotationView setCenter:center pitch:self.camera.pitch]; } } + + [CATransaction commit]; } - (void)enqueueAnnotationViewForAnnotationContext:(MGLAnnotationContext &)annotationContext