| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/ui/fullscreen/fullscreen_animator.h" |
| |
| #import <math.h> |
| #import <algorithm> |
| #import <memory> |
| |
| #import "base/check_op.h" |
| #import "ios/chrome/common/material_timing.h" |
| #import "ui/gfx/geometry/cubic_bezier.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| CGFloat GetFinalFullscreenProgressForAnimation(FullscreenAnimatorStyle style) { |
| return style == FullscreenAnimatorStyle::ENTER_FULLSCREEN ? 0.0 : 1.0; |
| } |
| |
| @interface FullscreenAnimator () { |
| // The bezier backing the timing curve. |
| std::unique_ptr<gfx::CubicBezier> _bezier; |
| // The current progress value that was recorded when the animator was stopped. |
| CGFloat _progressUponStopping; |
| } |
| @end |
| |
| @implementation FullscreenAnimator |
| @synthesize style = _style; |
| @synthesize startProgress = _startProgress; |
| @synthesize finalProgress = _finalProgress; |
| |
| - (instancetype)initWithStartProgress:(CGFloat)startProgress |
| style:(FullscreenAnimatorStyle)style { |
| // Control points for Material Design CurveEaseOut curve. |
| UICubicTimingParameters* timingParams = [[UICubicTimingParameters alloc] |
| initWithControlPoint1:CGPointMake(0.0, 0.0) |
| controlPoint2:CGPointMake(0.2, 0.1)]; |
| DCHECK_GE(startProgress, 0.0); |
| DCHECK_LE(startProgress, 1.0); |
| self = [super initWithDuration:kMaterialDuration1 |
| timingParameters:timingParams]; |
| if (self) { |
| DCHECK_GE(startProgress, 0.0); |
| DCHECK_LE(startProgress, 1.0); |
| _style = style; |
| _startProgress = startProgress; |
| _finalProgress = GetFinalFullscreenProgressForAnimation(_style); |
| _bezier = std::make_unique<gfx::CubicBezier>( |
| timingParams.controlPoint1.x, timingParams.controlPoint1.y, |
| timingParams.controlPoint2.x, timingParams.controlPoint2.y); |
| } |
| return self; |
| } |
| |
| #pragma mark Accessors |
| |
| - (CGFloat)currentProgress { |
| if (self.state == UIViewAnimatingStateStopped) |
| return _progressUponStopping; |
| CGFloat interpolationFraction = _bezier->Solve(self.fractionComplete); |
| CGFloat range = self.finalProgress - self.startProgress; |
| return self.startProgress + interpolationFraction * range; |
| } |
| |
| #pragma mark Public |
| |
| - (CGFloat)progressForAnimatingPosition:(UIViewAnimatingPosition)position { |
| switch (position) { |
| case UIViewAnimatingPositionStart: |
| return self.startProgress; |
| case UIViewAnimatingPositionEnd: |
| return self.finalProgress; |
| case UIViewAnimatingPositionCurrent: |
| return self.currentProgress; |
| } |
| } |
| |
| #pragma mark UIViewAnimating |
| |
| - (void)stopAnimation:(BOOL)withoutFinishing { |
| // Record the progress value when transitioning from the active to stopped |
| // state. This allows `currentProgress` to return the correct value after |
| // stopping, as `fractionComplete` is reset to 0.0 for stopped animators. |
| if (self.state == UIViewAnimatingStateActive) |
| _progressUponStopping = self.currentProgress; |
| if (_progressUponStopping == _startProgress) |
| return; |
| [super stopAnimation:withoutFinishing]; |
| } |
| |
| #pragma mark UIViewPropertyAnimator |
| |
| - (BOOL)isInterruptible { |
| return YES; |
| } |
| |
| @end |