Replicating the style of the iOS Mail App's Compose Function

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.


UPDATE - June 2018:

@ChristopherSwasey updated the repo to be compatible with Swift 4. Thanks Christopher!


For future travelers, Brian's post is excellent, but there's quite a bit of great information out there about UIPresentationController (which facilitates this animation) I'd highly recommend looking into. I've created a repo containing a working Swift 1.2 version of the iOS Mail app's compose animation. There are a ton of related resources I've also put in the ReadMe. Please check it out here:
https://github.com/kbpontius/iOSComposeAnimation