Удалить пользовательский UIStoryboardSegue с пользовательской анимацией

Я видел несколько примеров, как представить пользовательскую UIStoryboardSegue с пользовательской анимацией. По сути, вы создаете подкласс UIStoryBoardSegue и переопределяете метод «выполнить», т.е. вот так:

- (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];
                     }];
}

Но что мне делать, если я хочу пользовательскую анимацию при удалении перехода с экрана? Переопределите какой-либо другой метод в этом классе и вызовите его. Или выполнять анимацию в том месте, где я вызываю "dismissViewController", что кажется нелогичным?

Будем благодарны за ответ,

Артем


person Artem    schedule 26.10.2012    source источник


Ответы (2)


Для изменения анимации на dismissViewController вы должны установить modalTransitionStyle на UIModalTransitionStyle на presentedViewController.

- (IBAction)dismiss:(id)sender {
    self.presentingViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
person Pfitz    schedule 26.10.2012
comment
tnx за ответ, но я спросил о месте, где я должен создавать анимацию. Когда я представляю представление (модальное или push), я делаю это в методе выполнения, но когда я хочу отклонить его, я обычно вызываю rejectViewController в родительском делегате, это подходящее место для создания анимации. - person Artem; 26.10.2012
comment
хорошо, теперь я вижу ваше мнение. Но является ли хорошей практикой настраивать текущую анимацию в подклассе Segue и отключать анимацию в классе VC, как вы думаете? - person Artem; 26.10.2012
comment
насколько я знаю, нет другой возможности при отклонении viewController. Вы можете использовать ту же технику для представления контроллера представления, если хотите. Недостатком является то, что нет вариантов для пользовательских анимаций без некоторых трюков. - person Pfitz; 26.10.2012
comment
Но я думаю, что для пользовательских анимаций вы можете проделать тот же трюк, что и в моем примере кода. Не пробовал, но думаю должно сработать. - person Artem; 26.10.2012

Чтобы избежать каких-либо преобразований, вот код, который я успешно использую (кстати, ответ на Subview имеет неправильную ориентацию ):

#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
person Laurent Magnin    schedule 18.11.2012
comment
Спасибо за ответ, я думаю, что я делаю что-то подобное - person Artem; 26.11.2012