Andy
Andy

Reputation: 770

iOS - Creating a custom push segue animation

I am trying to create a push segue animation where the sourceVC drops down off screen vertically and the destinationVC appears upwards onto the screen vertically. My custom segue seems to almost make this animation, however, upon the destinationVC appearing the animation does not work. Here is my -perform segue.

-(void)perform
{
    UIViewController *sourceVC =  self.sourceViewController;
    UIViewController *destVC = self.destinationViewController;
    [sourceVC.view addSubview:destVC.view];

    float width = sourceVC.view.frame.size.width;
    float height = sourceVC.view.frame.size.height;

    destVC.view.frame = CGRectMake(0, 560, width, height);

    [UIView animateWithDuration:.2 delay:0 options:UIViewAnimationOptionCurveLinear
                     animations:^{
                         [destVC.view removeFromSuperview];
                         sourceVC.view.frame = CGRectMake(0, 560, width, height);
                     } completion:^(BOOL finished) {
                         [UIView animateWithDuration:.2 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
                             destVC.view.frame = CGRectMake(0, 0, destVC.view.frame.size.width, destVC.view.frame.size.height);
                         } completion:^(BOOL finished) {
                             [sourceVC.navigationController pushViewController:destVC animated:NO];
                         }];
                     }];
}

The second animation is the one that is not working.

Any ideas what is wrong with my code? Thanks for any help.

Upvotes: 3

Views: 1853

Answers (1)

Andy
Andy

Reputation: 770

I needed to create a custom Animator class that conformed to UIViewControllerAnimatedTransitioning.

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

@interface SAAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@end

I then implemented the required methods.

@implementation SAAnimator

-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 0.2;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        fromViewController.view.userInteractionEnabled = NO;

        [[transitionContext containerView]addSubview:fromViewController.view];
        [[transitionContext containerView]addSubview:toViewController.view];

    toViewController.view.frame = CGRectMake(0, 560, toViewController.view.frame.size.width, toViewController.view.frame.size.height);

        [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
            fromViewController.view.frame = CGRectMake(0, 560, fromViewController.view.frame.size.width, fromViewController.view.frame.size.height);
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
                toViewController.view.frame = CGRectMake(0, 0, toViewController.view.frame.size.width, toViewController.view.frame.size.height);
            } completion:^(BOOL finished) {
                [transitionContext completeTransition:YES];
            }];
        }];
}
@end

Then very simply, in my view controller performing the push segue, I made the class conform to the UINavigationControllerDelegate and implement this method.

#pragma mark - Animated Transiton

-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
    if (operation == UINavigationControllerOperationPush) {
        SAAnimator * animator = [SAAnimator new];
        return  animator;
    }
    return nil;
}

In prepareForSegue set the navigation controller's delegate

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"toCreateVC"]) {
        self.navigationController.delegate = self;
    }
}

Upvotes: 3

Related Questions