blob: 44986702140d649e7721087ba6344c8804d5fd24 [file] [log] [blame] [edit]
// Copyright 2016-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "MDCDialogTransitionController.h"
#import "MDCDialogPresentationController.h"
@implementation MDCDialogTransitionController
// The default duration of the dialog fade-in or fade-out animation
static const NSTimeInterval kDefaultOpacityTransitionDuration = 0.2;
// The default duration of the dialog scale-up or scale-down animation
static const NSTimeInterval kDefaultScaleTransitionDuration = 0;
// The default starting X and Y scale of the presented dialog
static const CGFloat kDefaultInitialScaleFactor = 1.0;
- (instancetype)init {
self = [super init];
if (self) {
_opacityAnimationDuration = kDefaultOpacityTransitionDuration;
_scaleAnimationDuration = kDefaultScaleTransitionDuration;
_dialogInitialScaleFactor = kDefaultInitialScaleFactor;
}
return self;
}
#pragma mark - UIViewControllerAnimatedTransitioning
- (NSTimeInterval)transitionDuration:
(__unused id<UIViewControllerContextTransitioning>)transitionContext {
return MAX(self.opacityAnimationDuration, self.scaleAnimationDuration);
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
// If a view in the transitionContext is nil, it likely hasn't been loaded by its ViewController
// yet. Ask for it directly to initiate a loadView on the ViewController.
UIViewController *fromViewController =
[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
if (fromView == nil) {
fromView = fromViewController.view;
}
UIViewController *toViewController =
[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
if (toView == nil) {
toView = toViewController.view;
}
UIViewController *toPresentingViewController = toViewController.presentingViewController;
BOOL presenting = (toPresentingViewController == fromViewController) ? YES : NO;
UIViewController *animatingViewController = presenting ? toViewController : fromViewController;
UIView *dialogView = presenting ? toView : fromView;
UIView *containerView = transitionContext.containerView;
if (presenting) {
[containerView addSubview:toView];
}
dialogView.frame = [transitionContext finalFrameForViewController:animatingViewController];
[CATransaction begin];
[CATransaction setCompletionBlock:^{
// If we're dismissing, remove the presented view from the hierarchy
if (!presenting) {
[fromView removeFromSuperview];
}
// From ADC : UIViewControllerContextTransitioning
// (https://developer.apple.com/documentation/uikit/uiviewcontrollercontexttransitioning/1622042-completetransition)
// When you do create transition animations, always call the
// completeTransition: from an appropriate completion block to let UIKit know
// when all of your animations have finished.
[transitionContext completeTransition:YES];
}];
UIViewAnimationOptions options =
UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState;
// Opacity animation
CGFloat startingAlpha = presenting ? 0 : 1;
CGFloat endingAlpha = presenting ? 1 : 0;
dialogView.alpha = startingAlpha;
[UIView animateWithDuration:self.opacityAnimationDuration
delay:0
options:options
animations:^{
dialogView.alpha = endingAlpha;
}
completion:nil];
// Scale animation
MDCDialogPresentationController *presentationController = nil;
if ([animatingViewController.presentationController
isKindOfClass:[MDCDialogPresentationController class]]) {
presentationController =
(MDCDialogPresentationController *)animatingViewController.presentationController;
}
CGAffineTransform startingTransform =
presenting
? CGAffineTransformMakeScale(self.dialogInitialScaleFactor, self.dialogInitialScaleFactor)
: CGAffineTransformIdentity;
CGAffineTransform endingTransform = CGAffineTransformIdentity;
dialogView.transform = startingTransform;
presentationController.dialogTransform = startingTransform;
UIViewAnimationOptions scaleAnimationOptions = options | UIViewAnimationOptionCurveEaseOut;
[UIView animateWithDuration:self.scaleAnimationDuration
delay:0
options:scaleAnimationOptions
animations:^{
dialogView.transform = endingTransform;
presentationController.dialogTransform = endingTransform;
}
completion:nil];
[CATransaction commit];
}
#pragma mark - UIViewControllerTransitioningDelegate
- (UIPresentationController *)
presentationControllerForPresentedViewController:(UIViewController *)presented
presentingViewController:(UIViewController *)presenting
sourceViewController:(__unused UIViewController *)source {
return [[MDCDialogPresentationController alloc] initWithPresentedViewController:presented
presentingViewController:presenting];
}
- (id<UIViewControllerAnimatedTransitioning>)
animationControllerForPresentedController:(__unused UIViewController *)presented
presentingController:(__unused UIViewController *)presenting
sourceController:(__unused UIViewController *)source {
return self;
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:
(__unused UIViewController *)dismissed {
return self;
}
@end