Implement custom animation to present modal view from specified view on iPad

Zebs picture Zebs · Jul 7, 2011 · Viewed 18.6k times · Source

On the iPad we get much more room to work with, so presenting full screen modal views is not ideal.

I know how to present modal views in the new formSheet and a close approach can be found on this question: iPad iTunes Animation

The problem is that you cannot choose where the animation will come from, so it just defaults and appears from the center, I want to customize it so that it appears from a specific location.

The best example I can find for this animation can be seen on the first few seconds of this video

If anyone can point me on the right direction using code, tutorials or documentation I would greatly appreciate it!

Update:

After some investigation I have found that this can be done using layers and Core Animation for the first part; and then animate it a formSheet modal view but I still dont quite understand how to achieve it, hopefully you guys can help!

Answer

Mihai Fratu picture Mihai Fratu · Jul 13, 2011

What I did was creating a new category for UIViewController as follows

UIViewController+ShowModalFromView.h

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

@interface UIViewController (ShowModalFromView)

- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view;

@end

UIViewController+ShowModalFromView.m

#import "UIViewController+ShowModalFromView.h"

@implementation UIViewController (ShowModalFromView)

- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view
{
    modalViewController.modalPresentationStyle = UIModalPresentationFormSheet;

    // Add the modal viewController but don't animate it. We will handle the animation manually
    [self presentModalViewController:modalViewController animated:NO];

    // Remove the shadow. It causes weird artifacts while animating the view.
    CGColorRef originalShadowColor = modalViewController.view.superview.layer.shadowColor;
    modalViewController.view.superview.layer.shadowColor = [[UIColor clearColor] CGColor];

    // Save the original size of the viewController's view    
    CGRect originalFrame = modalViewController.view.superview.frame;

    // Set the frame to the one of the view we want to animate from
    modalViewController.view.superview.frame = view.frame;

    // Begin animation
    [UIView animateWithDuration:1.0f
                     animations:^{
                         // Set the original frame back
                         modalViewController.view.superview.frame = originalFrame;
                     }
                     completion:^(BOOL finished) {
                         // Set the original shadow color back after the animation has finished
                         modalViewController.view.superview.layer.shadowColor = originalShadowColor;
                     }];
}

@end

It's pretty straight forward. Please let me know if this helps you.

UPDATE

I've updated the answer to use animation blocks instead of [UIView beginAnimations:nil context:nil]; / [UIView commitAnimations] pair.