This effect can be achieved with UIPresentationController
, made available in iOS 8. Apple has a WWDC '14 video on this topic as well as some useful sample code found at the bottom of this post (original link I had posted here no longer works).
*The demo is called "LookInside: Presentation Controllers Adaptivity and Custom Animator Objects." There are a couple bugs in Apple's code that correspond to outdated API usage, which can be solved by changing the broken method name (in multiple places) to the following:
initWithPresentedViewController:presentingViewController:
Here's what you can do to replicate the animation on the iOS 8 mail app. To achieve the desired effect, download the project I mentioned above, and then all you have to do is change a couple things.
First, go to AAPLOverlayPresentationController.m and make sure you've implemented the frameOfPresentedViewInContainerView
method. Mine looks something like this:
- (CGRect)frameOfPresentedViewInContainerView
{
CGRect containerBounds = [[self containerView] bounds];
CGRect presentedViewFrame = CGRectZero;
presentedViewFrame.size = CGSizeMake(containerBounds.size.width, containerBounds.size.height-40.0f);
presentedViewFrame.origin = CGPointMake(0.0f, 40.0f);
return presentedViewFrame;
}
The key is that you want the frame of the presentedViewController to be offset from the top of the screen so you can achieve the look of one view controller overlapping the other (without having the modal fully cover the presentingViewController).
Next, find the animateTransition:
method in AAPLOverlayTransitioner.m and replace the code with the code below. You may want to tweak a few things based on your own code, but overall, this appears to be the solution:
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIView *fromView = [fromVC view];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *toView = [toVC view];
UIView *containerView = [transitionContext containerView];
BOOL isPresentation = [self isPresentation];
if(isPresentation)
{
[containerView addSubview:toView];
}
UIViewController *bottomVC = isPresentation? fromVC : toVC;
UIView *bottomPresentingView = [bottomVC view];
UIViewController *topVC = isPresentation? toVC : fromVC;
UIView *topPresentedView = [topVC view];
CGRect topPresentedFrame = [transitionContext finalFrameForViewController:topVC];
CGRect topDismissedFrame = topPresentedFrame;
topDismissedFrame.origin.y += topDismissedFrame.size.height;
CGRect topInitialFrame = isPresentation ? topDismissedFrame : topPresentedFrame;
CGRect topFinalFrame = isPresentation ? topPresentedFrame : topDismissedFrame;
[topPresentedView setFrame:topInitialFrame];
[UIView animateWithDuration:[self transitionDuration:transitionContext]
delay:0
usingSpringWithDamping:300.0
initialSpringVelocity:5.0
options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState
animations:^{
[topPresentedView setFrame:topFinalFrame];
CGFloat scalingFactor = [self isPresentation] ? 0.92f : 1.0f;
//this is the magic right here
bottomPresentingView.transform = CGAffineTransformScale(CGAffineTransformIdentity, scalingFactor, scalingFactor);
}
completion:^(BOOL finished){
if(![self isPresentation])
{
[fromView removeFromSuperview];
}
[transitionContext completeTransition:YES];
}];
}
I don't, at this time, have a solution for OS versions prior to iOS 8, but please feel free to add an answer if you come up with one. Thanks.
UPDATE (03/2016):
It appears as though the link above no longer works. The same project can be found here: https://developer.apple.com/library/ios/samplecode/LookInside/LookInsidePresentationControllersAdaptivityandCustomAnimatorObjects.zip
UPDATE (12/2019):
It appears as though this transition style is now the default behavior when presenting view controllers modally on iOS 13. I'm not positive about previous versions of the OS, but if you want to replicate this functionality / transition in your own apps without writing lots of code, you can either just present a view controller on iOS 13 as-is, or you can set that view controller's modalPresentationStyle
to .pageSheet
and then present it.