Commit 526a092f authored by Gauthier Ambard's avatar Gauthier Ambard Committed by Commit Bot

[iOS] Change the NTP animation to use an animator

This CL updates how the NTP animations to shift tiles up (i.e. when the
omnibox is focused), using an animator instead of the regular UIView
-animate:completion:.
It allows to stop the animation in the middle without having the
animated properties in an undefined state.

Bug: 1101331
Change-Id: Iadff66283784c7a339770b58270099678cf2616c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2278253
Commit-Queue: Gauthier Ambard <gambard@chromium.org>
Reviewed-by: default avatarStepan Khapugin <stkhapugin@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#784857}
parent 0bde436b
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_SYNCHRONIZING_H_ #ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_SYNCHRONIZING_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_SYNCHRONIZING_H_ #define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CONTENT_SUGGESTIONS_COLLECTION_SYNCHRONIZING_H_
#import <UIKit/UIKit.h>
#import "base/ios/block_types.h" #import "base/ios/block_types.h"
// Synchronization protocol used by the ContentSuggestions header controller to // Synchronization protocol used by the ContentSuggestions header controller to
...@@ -17,7 +19,8 @@ ...@@ -17,7 +19,8 @@
// when the collection is scrolled to top. |animations| is called only if it is // when the collection is scrolled to top. |animations| is called only if it is
// not yet scrolled to the top. // not yet scrolled to the top.
- (void)shiftTilesUpWithAnimations:(ProceduralBlock)animations - (void)shiftTilesUpWithAnimations:(ProceduralBlock)animations
completion:(ProceduralBlock)completion; completion:
(void (^)(UIViewAnimatingPosition))completion;
// Notifies the collection that its layout has changed and should be // Notifies the collection that its layout has changed and should be
// invalidated. // invalidated.
- (void)invalidateLayout; - (void)invalidateLayout;
......
...@@ -37,6 +37,8 @@ const CGFloat kShiftTilesUpAnimationDuration = 0.25; ...@@ -37,6 +37,8 @@ const CGFloat kShiftTilesUpAnimationDuration = 0.25;
// Tap gesture recognizer when the omnibox is focused. // Tap gesture recognizer when the omnibox is focused.
@property(nonatomic, strong) UITapGestureRecognizer* tapGestureRecognizer; @property(nonatomic, strong) UITapGestureRecognizer* tapGestureRecognizer;
// Animator for the shiftTilesUp animation.
@property(nonatomic, strong) UIViewPropertyAnimator* animator;
@end @end
@implementation ContentSuggestionsHeaderSynchronizer @implementation ContentSuggestionsHeaderSynchronizer
...@@ -81,6 +83,12 @@ initWithCollectionController: ...@@ -81,6 +83,12 @@ initWithCollectionController:
self.shouldAnimateHeader = YES; self.shouldAnimateHeader = YES;
if (self.animator.running) {
[self.animator stopAnimation:NO];
[self.animator finishAnimationAtPosition:UIViewAnimatingPositionStart];
self.animator = nil;
}
if (self.collectionShiftingOffset == 0 || self.collectionView.dragging) { if (self.collectionShiftingOffset == 0 || self.collectionView.dragging) {
self.collectionShiftingOffset = 0; self.collectionShiftingOffset = 0;
[self updateFakeOmniboxOnCollectionScroll]; [self updateFakeOmniboxOnCollectionScroll];
...@@ -103,7 +111,8 @@ initWithCollectionController: ...@@ -103,7 +111,8 @@ initWithCollectionController:
} }
- (void)shiftTilesUpWithAnimations:(ProceduralBlock)animations - (void)shiftTilesUpWithAnimations:(ProceduralBlock)animations
completion:(ProceduralBlock)completion { completion:
(void (^)(UIViewAnimatingPosition))completion {
// Add gesture recognizer to collection view when the omnibox is focused. // Add gesture recognizer to collection view when the omnibox is focused.
[self.collectionView addGestureRecognizer:self.tapGestureRecognizer]; [self.collectionView addGestureRecognizer:self.tapGestureRecognizer];
...@@ -117,7 +126,7 @@ initWithCollectionController: ...@@ -117,7 +126,7 @@ initWithCollectionController:
if (self.collectionController.scrolledToTop) { if (self.collectionController.scrolledToTop) {
self.shouldAnimateHeader = NO; self.shouldAnimateHeader = NO;
if (completion) if (completion)
completion(); completion(UIViewAnimatingPositionEnd);
return; return;
} }
...@@ -131,29 +140,43 @@ initWithCollectionController: ...@@ -131,29 +140,43 @@ initWithCollectionController:
self.collectionController.scrolledToTop = YES; self.collectionController.scrolledToTop = YES;
self.shouldAnimateHeader = YES; self.shouldAnimateHeader = YES;
[UIView animateWithDuration:kShiftTilesUpAnimationDuration __weak __typeof(self) weakSelf = self;
animations:^{
if (self.collectionView.contentOffset.y < pinnedOffsetY) { self.animator = [[UIViewPropertyAnimator alloc]
if (animations) initWithDuration:kShiftTilesUpAnimationDuration
animations(); curve:UIViewAnimationCurveEaseInOut
// Changing the contentOffset of the collection results in a scroll animations:^{
// and a change in the constraints of the header. if (!weakSelf)
self.collectionView.contentOffset = CGPointMake(0, pinnedOffsetY); return;
// Layout the header for the constraints to be animated.
[self.headerController layoutHeader]; __typeof(weakSelf) strongSelf = weakSelf;
[self.collectionView.collectionViewLayout invalidateLayout]; if (strongSelf.collectionView.contentOffset.y < pinnedOffsetY) {
} if (animations)
} animations();
completion:^(BOOL finished) { // Changing the contentOffset of the collection results in a
// Check to see if the collection are still scrolled to the top -- it's // scroll and a change in the constraints of the header.
// possible (and difficult) to unfocus the omnibox and initiate a strongSelf.collectionView.contentOffset =
// -shiftTilesDown before the animation here completes. CGPointMake(0, pinnedOffsetY);
if (self.collectionController.scrolledToTop) { // Layout the header for the constraints to be animated.
self.shouldAnimateHeader = NO; [strongSelf.headerController layoutHeader];
if (completion) [strongSelf.collectionView
completion(); .collectionViewLayout invalidateLayout];
} }
}]; }];
[self.animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
if (!weakSelf)
return;
if (finalPosition == UIViewAnimatingPositionEnd)
weakSelf.shouldAnimateHeader = NO;
if (completion)
completion(finalPosition);
}];
self.animator.interruptible = YES;
[self.animator startAnimation];
} }
- (void)invalidateLayout { - (void)invalidateLayout {
......
...@@ -547,17 +547,24 @@ using base::UserMetricsAction; ...@@ -547,17 +547,24 @@ using base::UserMetricsAction;
}; };
} }
void (^completionBlock)() = ^{ void (^completionBlock)(UIViewAnimatingPosition) =
self.headerView.omnibox.hidden = YES; ^(UIViewAnimatingPosition finalPosition) {
self.headerView.cancelButton.hidden = YES; self.headerView.omnibox.hidden = YES;
self.headerView.searchHintLabel.alpha = 1; self.headerView.cancelButton.hidden = YES;
self.headerView.voiceSearchButton.alpha = 1; self.headerView.searchHintLabel.alpha = 1;
self.disableScrollAnimation = NO; self.headerView.voiceSearchButton.alpha = 1;
[self.dispatcher fakeboxFocused]; self.disableScrollAnimation = NO;
if (IsSplitToolbarMode()) { if (finalPosition == UIViewAnimatingPositionEnd &&
[self.dispatcher onFakeboxAnimationComplete]; [self.delegate isScrolledToTop]) {
} // Check to see if the collection are still scrolled to the top --
}; // it's possible (and difficult) to unfocus the omnibox and initiate a
// -shiftTilesDown before the animation here completes.
[self.dispatcher fakeboxFocused];
if (IsSplitToolbarMode()) {
[self.dispatcher onFakeboxAnimationComplete];
}
}
};
[self.collectionSynchronizer shiftTilesUpWithAnimations:animations [self.collectionSynchronizer shiftTilesUpWithAnimations:animations
completion:completionBlock]; completion:completionBlock];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment