使用自定义动画删除自定义 UIStoryboardSegue

Posted

技术标签:

【中文标题】使用自定义动画删除自定义 UIStoryboardSegue【英文标题】:Remove custom UIStoryboardSegue with custom animation 【发布时间】:2012-10-26 08:12:05 【问题描述】:

我已经看到了几个如何使用自定义动画呈现自定义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];
                     ];

但是如果我想要自定义动画同时从屏幕上移除 Segue,我该怎么办?覆盖这个类中的一些其他方法并调用它。或者在我叫“dismissViewController”的地方做动画,感觉不合逻辑?

不胜感激,

阿尔乔姆

【问题讨论】:

【参考方案1】:

要更改dismissViewController 上的动画,您必须将presentedViewController 上的modalTransitionStyle 设置为UIModalTransitionStyle

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

【讨论】:

tnx 的答案,但我问我应该创建动画的地方。当我呈现一个视图(模态或推送)时,我在 perform 方法中执行它,但是当我想解除它时,我通常在父代理中调用dismissViewController,它是在那里创建动画的合适位置吗? 好的,现在我看到你的意见了。但是在 Segue 子类中设置当前动画并在 VC 类中关闭动画是否是一种好习惯,您怎么看? 据我所知,关闭 viewController 时没有其他可能性。如果需要,您可以使用相同的技术来呈现视图控制器。缺点是没有做一些技巧就没有自定义动画的选项。 但我认为对于自定义动画,您可以使用与我的示例代码相同的技巧。没试过,但我认为应该可以。【参考方案2】:

为避免任何转换,这是我成功使用的代码(顺便说一句,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

【讨论】:

谢谢你的回答,我想我做的有点类似

以上是关于使用自定义动画删除自定义 UIStoryboardSegue的主要内容,如果未能解决你的问题,请参考以下文章

使用 UIStoryBoard 基于自定义 URL 方案处理屏幕

UIStoryboard 中的自定义原型单元已创建,但未显示在 UITableView

使用删除与隐藏时未调用自定义动画

自定义 UINavigationItem 类 - 标题取决于 Active UIStoryboard

不使用 Storyboard segues 的自定义视图转换 (Swift)

如何在 Swift 3 中加载/删除带有动画的自定义视图