Artem
Artem

Reputation: 939

Remove custom UIStoryboardSegue with custom animation

I have seen several examples how to present a custom UIStoryboardSegue with custom animation. Basically, you subclass UIStoryBoardSegue and override "perform" method, i.e. like this:

- (void)perform
{
    UIViewController *source = self.sourceViewController;
    UIViewController *destination = self.destinationViewController;

    // Create a UIImage with the contents of the destination
    UIGraphicsBeginImageContext(destination.view.bounds.size);
    [destination.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *destinationImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    // Add this image as a subview to the tab bar controller
    UIImageView *destinationImageView = [[UIImageView alloc] initWithImage:destinationImage];
    [source.parentViewController.view addSubview:destinationImageView];

    // Scale the image down and rotate it 180 degrees (upside down)
    CGAffineTransform scaleTransform = CGAffineTransformMakeScale(0.1, 0.1);
    CGAffineTransform rotateTransform = CGAffineTransformMakeRotation(M_PI);
    destinationImageView.transform = CGAffineTransformConcat(scaleTransform, rotateTransform);

    // Move the image outside the visible area
    CGPoint oldCenter = destinationImageView.center;
    CGPoint newCenter = CGPointMake(oldCenter.x - destinationImageView.bounds.size.width, oldCenter.y);
    destinationImageView.center = newCenter;

    // Start the animation
    [UIView animateWithDuration:0.5f
                          delay:0
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^(void) {
                         destinationImageView.transform = CGAffineTransformIdentity;
                         destinationImageView.center = oldCenter;
                     }
                     completion: ^(BOOL done) {
                         // Remove the image as we no longer need it
                         [destinationImageView removeFromSuperview];

                         // Properly present the new screen
                         [source presentViewController:destination animated:NO completion:nil];
                     }];
}

But what should I do if I want custom animation while removing Segue from the screen? Override some other method in this class and call it. Or perform animation at the place, where I call "dismissViewController", which feels not logical?

Will be grateful for the answer,

Artem

Upvotes: 0

Views: 1145

Answers (2)

Laurent Magnin
Laurent Magnin

Reputation: 397

To avoid any transformation, here is the code I successfully use (btw answer to Subview has wrong orientation ):

#include <QuartzCore/QuartzCore.h>

@implementation HorizontalSwipingSegue

- (void) perform {
    UIViewController *source = self.sourceViewController;
    UIViewController *destination = self.destinationViewController;    
    UIView *sourceView = source.view;
    UIView *destinationView = destination.view;

    // Create a UIImageView with the contents of the source
    UIGraphicsBeginImageContext(sourceView.bounds.size);
    [sourceView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *sourceImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    UIImageView *sourceImageView = [[UIImageView alloc] initWithImage:sourceImage];

    [[self sourceViewController] presentViewController:[self destinationViewController] animated:NO completion:NULL];

    CGPoint destinationViewFinalCenter = CGPointMake(destinationView.center.x, destinationView.center.y);
    CGFloat deltaX = destinationView.frame.size.width;
    CGFloat deltaY = destinationView.frame.size.height;

    switch (((UIViewController *)self.sourceViewController).interfaceOrientation) {
       case UIDeviceOrientationPortrait:
            destinationView.center = CGPointMake(destinationView.center.x - deltaX, destinationView.center.y);                
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaX, sourceImageView.center.y);
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            destinationView.center = CGPointMake(destinationView.center.x + deltaX, destinationView.center.y);
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaX, sourceImageView.center.y);
            break;
        case UIDeviceOrientationLandscapeLeft:
            destinationView.center = CGPointMake(destinationView.center.x, destinationView.center.y - deltaY);                
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaY, sourceImageView.center.y);
            break;
        case UIDeviceOrientationLandscapeRight:
            destinationView.center = CGPointMake(destinationView.center.x, destinationView.center.y + deltaY);
            sourceImageView.center = CGPointMake(sourceImageView.center.x + deltaY, sourceImageView.center.y);
            break;
    }

    [destinationView addSubview:sourceImageView];

    [UIView animateWithDuration:0.6f
                     animations:^{
                         destinationView.center = destinationViewFinalCenter; 
                     }
                     completion:^(BOOL finished){
                         [sourceImageView removeFromSuperview];
                     }];
}

@end

Upvotes: 1

Pfitz
Pfitz

Reputation: 7344

For changing the animation on a dismissViewController you have to set the modalTransitionStyle to a UIModalTransitionStyle on the presentedViewController.

- (IBAction)dismiss:(id)sender {
    self.presentingViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}

Upvotes: 1

Related Questions