1// Copyright 2019 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "ios/chrome/browser/ui/scanner/scanner_transitioning_delegate.h" 6 7#include "base/ios/block_types.h" 8 9#if !defined(__has_feature) || !__has_feature(objc_arc) 10#error "This file requires ARC support." 11#endif 12 13namespace { 14 15// The default animation duration. 16const NSTimeInterval kDefaultDuration = 0.25; 17 18enum ScannerTransition { PRESENT, DISMISS }; 19 20} // namespace 21 22// Animates the Scanner transition. If initialized with the |PRESENT| 23// transition, positions the Scanner view below its presenting view 24// controller's view in the container view and animates the presenting view to 25// slide up. If initialized with the |DISMISS| transition, positions the 26// presenting view controller's view above the Scanner view in the container 27// view and animates the presenting view to slide down. 28@interface ScannerTransitionAnimator 29 : NSObject <UIViewControllerAnimatedTransitioning> { 30 ScannerTransition _transition; 31} 32 33- (instancetype)initWithTransition:(ScannerTransition)transition; 34 35@end 36 37@implementation ScannerTransitionAnimator 38 39- (instancetype)initWithTransition:(ScannerTransition)transition { 40 self = [super init]; 41 if (self) { 42 _transition = transition; 43 } 44 return self; 45} 46 47- (void)animateTransition: 48 (id<UIViewControllerContextTransitioning>)transitionContext { 49 UIView* containerView = [transitionContext containerView]; 50 UIView* presentedView = 51 [transitionContext viewForKey:UITransitionContextToViewKey]; 52 UIView* presentingView = 53 [transitionContext viewForKey:UITransitionContextFromViewKey]; 54 55 // Get the final frame for the presented view. 56 UIViewController* presentedViewController = [transitionContext 57 viewControllerForKey:UITransitionContextToViewControllerKey]; 58 CGRect finalFrame = 59 [transitionContext finalFrameForViewController:presentedViewController]; 60 61 ProceduralBlock animations; 62 63 // Set the frame for the presented view. 64 presentedView.frame = finalFrame; 65 [presentedView layoutIfNeeded]; 66 67 switch (_transition) { 68 case PRESENT: { 69 [containerView insertSubview:presentedView belowSubview:presentingView]; 70 animations = ^void { 71 presentingView.transform = 72 CGAffineTransformMakeTranslation(0, -finalFrame.size.height); 73 }; 74 break; 75 } 76 case DISMISS: { 77 [containerView insertSubview:presentedView aboveSubview:presentingView]; 78 presentedView.transform = 79 CGAffineTransformMakeTranslation(0, -finalFrame.size.height); 80 animations = ^void { 81 presentedView.transform = CGAffineTransformIdentity; 82 }; 83 break; 84 } 85 } 86 87 void (^completion)(BOOL) = ^void(BOOL finished) { 88 presentingView.transform = CGAffineTransformIdentity; 89 [transitionContext completeTransition:finished]; 90 }; 91 92 // Animate the transition. 93 [UIView animateWithDuration:kDefaultDuration 94 delay:0 95 options:UIViewAnimationOptionCurveEaseInOut 96 animations:animations 97 completion:completion]; 98} 99 100- (void)animationEnded:(BOOL)transitionCompleted { 101 return; 102} 103 104- (NSTimeInterval)transitionDuration: 105 (id<UIViewControllerContextTransitioning>)transitionContext { 106 return kDefaultDuration; 107} 108 109@end 110 111@implementation ScannerTransitioningDelegate 112 113- (id<UIViewControllerAnimatedTransitioning>) 114 animationControllerForPresentedController:(UIViewController*)presented 115 presentingController:(UIViewController*)presenting 116 sourceController:(UIViewController*)source { 117 return [[ScannerTransitionAnimator alloc] initWithTransition:PRESENT]; 118} 119 120- (id<UIViewControllerAnimatedTransitioning>) 121 animationControllerForDismissedController:(UIViewController*)dismissed { 122 return [[ScannerTransitionAnimator alloc] initWithTransition:DISMISS]; 123} 124 125@end 126