blob: 055c7102b0e2f984fa63921913ddc075d2bf0182 [file] [log] [blame]
// Copyright 2017-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 <CoreGraphics/CoreGraphics.h>
#import <QuartzCore/QuartzCore.h>
#import "MDCMaskedPresentationController.h"
#import <MotionTransitioning/MotionTransitioning.h>
#import <MotionAnimator/MotionAnimator.h>
#import "MDCMaskedTransitionMotionForContext.h"
@implementation MDCMaskedPresentationController {
CGRect (^_calculateFrameOfPresentedView)(UIPresentationController *);
CGFloat _initialSourceViewAlpha;
}
- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController
presentingViewController:(UIViewController *)presentingViewController
calculateFrameOfPresentedView:(CGRect (^)(UIPresentationController *))calculateFrameOfPresentedView
sourceView:(UIView *)sourceView {
self = [super initWithPresentedViewController:presentedViewController
presentingViewController:presentingViewController];
if (self) {
_scrimView = [[UIView alloc] init];
_scrimView.autoresizingMask = (UIViewAutoresizingFlexibleWidth
| UIViewAutoresizingFlexibleHeight);
_scrimView.backgroundColor = [UIColor colorWithWhite:0 alpha:(CGFloat)0.3];
_calculateFrameOfPresentedView = [calculateFrameOfPresentedView copy];
_sourceView = sourceView;
}
return self;
}
- (CGRect)frameOfPresentedViewInContainerView {
if (_calculateFrameOfPresentedView) {
return _calculateFrameOfPresentedView(self);
} else {
return self.containerView.bounds;
}
}
- (BOOL)shouldRemovePresentersView {
// We don't have access to the container view when this method is called, so we can only guess as
// to whether we'll be presenting full screen by checking for the presence of a frame calculation
// block.
BOOL definitelyFullscreen = _calculateFrameOfPresentedView == nil;
// Returning true here will cause UIKit to invoke viewWillDisappear and viewDidDisappear on the
// presenting view controller, and the presenting view controller's view will be removed on
// completion of the transition.
return definitelyFullscreen;
}
- (void)presentationTransitionWillBegin {
self.scrimView.frame = self.containerView.bounds;
[self.containerView addSubview:self.scrimView];
_initialSourceViewAlpha = self.sourceView.alpha;
MDCMaskedTransitionMotionSpec motionSpecification =
MDCMaskedTransitionMotionSpecForContext(self.containerView, self.presentedViewController);
MDCMaskedTransitionMotionTiming motionTiming = motionSpecification.expansion;
MDMMotionAnimator *animator = [[MDMMotionAnimator alloc] init];
[animator animateWithTiming:motionTiming.scrimFade
toLayer:self.scrimView.layer
withValues:@[ @0, @1 ]
keyPath:MDMKeyPathOpacity];
}
- (void)dismissalTransitionWillBegin {
MDCMaskedTransitionMotionSpec motionSpecification =
MDCMaskedTransitionMotionSpecForContext(self.containerView, self.presentedViewController);
if (motionSpecification.shouldSlideWhenCollapsed) {
// Immediately reveal the source view because our presented view controller isn't collapsing
// back to it.
self.sourceView.alpha = _initialSourceViewAlpha;
[self.presentedViewController.transitionCoordinator
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
self.scrimView.alpha = 0;
} completion:nil];
} else {
MDCMaskedTransitionMotionTiming motionTiming = motionSpecification.collapse;
MDMMotionAnimator *animator = [[MDMMotionAnimator alloc] init];
[animator animateWithTiming:motionTiming.scrimFade
toLayer:self.scrimView.layer
withValues:@[ @1, @0 ]
keyPath:MDMKeyPathOpacity];
}
}
- (void)dismissalTransitionDidEnd:(BOOL)completed {
if (completed) {
[self.scrimView removeFromSuperview];
self.scrimView = nil;
self.sourceView.alpha = _initialSourceViewAlpha;
self.sourceView = nil;
} else {
self.scrimView.alpha = 1;
self.sourceView.alpha = 0;
}
}
@end