【问题标题】:Change animation transition改变动画过渡
【发布时间】:2012-03-17 20:05:44
【问题描述】:

我有一个带有NavigationController 的应用程序。如何更改pushViewControllerpopToViewController 的动画过渡样式?

更新

我在@lawicko 答案中创建了类别。但是当我尝试调用函数时出现错误

[self.navigationController pushViewController:places withCustomTransition:CustomViewAnimationTransitionPush subtype:CustomViewAnimationSubtypeFromLeft];

错误是:“使用未声明的标识符'CustomViewAnimationTransitionPush'”

我应该在哪里声明这部分:

typedef enum {
    CustomViewAnimationTransitionNone,
    CustomViewAnimationTransitionFlipFromLeft,
    CustomViewAnimationTransitionFlipFromRight,
    CustomViewAnimationTransitionCurlUp,
    CustomViewAnimationTransitionCurlDown,
    CustomViewAnimationTransitionFadeIn,
    CustomViewAnimationTransitionMoveIn,
    CustomViewAnimationTransitionPush,
    CustomViewAnimationTransitionReveal
} CustomViewAnimationTransition;

现在写我在UINavigationController+Additions.h声明它

UPD 2:又一个新错误:

Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_CATransition", referenced from:
      objc-class-ref in UINavigationController+Additions.o
  "_kCATransition", referenced from:

所有 _kCATransitions 的错误都相同

【问题讨论】:

  • 你试过了吗? [1]:*.com/questions/3699882/…
  • 没关系,但我想要像后退按钮一样的动画.. 但为 pushViewController 设置它
  • 我不太明白。您希望单击返回 (popViewController) 时的动画成为推送视图 (pushViewController) 时的动画吗?
  • 是的!我想要像水平滑动这样的动画。但方向向左

标签: ios animation uinavigationcontroller pushviewcontroller popviewcontroller


【解决方案1】:

查看我创建的 UINavigationController 类别。它允许您使用几乎所有可能的转换进行推送和弹出,并且还支持 QuartzCore 转换的子类型,这将允许您完全按照您的意愿进行操作 - 从左侧推送视图。这样做:

[self.navigationController pushViewController:[[MyController alloc] init] withCustomTransition:CustomViewAnimationTransitionPush subtype:CustomViewAnimationSubtypeFromLeft];

代码如下。第一部分你需要放在标题部分:

// IMPORTANT - basic transitions like flip and curl are local, they reside only in animation block. Core animations however,
// once assigned to the layer, stay until changed or reset (by assigning nil as layer animation property)

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

typedef enum {
    CustomViewAnimationTransitionNone,
    CustomViewAnimationTransitionFlipFromLeft,
    CustomViewAnimationTransitionFlipFromRight,
    CustomViewAnimationTransitionCurlUp,
    CustomViewAnimationTransitionCurlDown,
    CustomViewAnimationTransitionFadeIn,
    CustomViewAnimationTransitionMoveIn,
    CustomViewAnimationTransitionPush,
    CustomViewAnimationTransitionReveal
} CustomViewAnimationTransition;

#define CustomViewAnimationSubtypeFromRight kCATransitionFromRight
#define CustomViewAnimationSubtypeFromLeft kCATransitionFromLeft
#define CustomViewAnimationSubtypeFromTop kCATransitionFromTop
#define CustomViewAnimationSubtypeFromBottom kCATransitionFromBottom

@interface UINavigationController(Additions)

- (void)pushViewController:(UIViewController *)viewController withCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype;

- (void)popViewControllerWithCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype;
- (void)popToRootViewControllerWithCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype;
- (void)popToViewController:(UIViewController *)viewController withCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype;

@end

您需要将第二部分放入实现文件中:

#import "UINavigationController_Additions.h"

@interface UINavigationController()

- (void)standardAnimationWithController:(UIViewController*)viewController
                                duration:(NSTimeInterval)duration
                                options:(UIViewAnimationOptions)options
                                changesBlock:(void (^)(void))block;
- (void)coreAnimationWithController:(UIViewController*)viewController
                                duration:(NSTimeInterval)duration
                                type:(NSString*)type
                                subtype:(NSString*)subtype
                                changesBlock:(void (^)(void))block;
@end

@implementation UINavigationController(Additions)

#pragma mark -
#pragma mark pushing

- (void)pushViewController:(UIViewController *)viewController withCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype {
    switch (transition) {
        case CustomViewAnimationTransitionNone:{
            [self standardAnimationWithController:viewController duration:.5 options:UIViewAnimationOptionTransitionNone
                                            changesBlock:^{
                                                [self pushViewController:viewController animated:NO];
                                            }];
            break;}
        case CustomViewAnimationTransitionFlipFromLeft:{
            [self standardAnimationWithController:viewController duration:.5 options:UIViewAnimationOptionTransitionFlipFromLeft
                                            changesBlock:^{
                                                [self pushViewController:viewController animated:NO];
                                            }];
            break;}
        case CustomViewAnimationTransitionFlipFromRight:{
            [self standardAnimationWithController:viewController duration:.5 options:UIViewAnimationOptionTransitionFlipFromRight
                                            changesBlock:^{
                                                [self pushViewController:viewController animated:NO];
                                            }];
            break;}
        case CustomViewAnimationTransitionCurlUp:{
            [self standardAnimationWithController:viewController duration:.5 options:UIViewAnimationOptionTransitionCurlUp
                                            changesBlock:^{
                                                [self pushViewController:viewController animated:NO];
                                            }];
            break;}
        case CustomViewAnimationTransitionCurlDown:{
            [self standardAnimationWithController:viewController duration:.5 options:UIViewAnimationOptionTransitionCurlDown
                                            changesBlock:^{
                                                [self pushViewController:viewController animated:NO];
                                            }];
            break;}
        case CustomViewAnimationTransitionFadeIn:{
            [self coreAnimationWithController:viewController duration:.5 type:kCATransitionFade subtype:nil
                                 changesBlock:^{
                                     [self pushViewController:viewController animated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionMoveIn:{
            [self coreAnimationWithController:viewController duration:.5 type:kCATransitionMoveIn subtype:subtype
                                 changesBlock:^{
                                     [self pushViewController:viewController animated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionPush:{
            [self coreAnimationWithController:viewController duration:.5 type:kCATransitionPush subtype:subtype
                                 changesBlock:^{
                                     [self pushViewController:viewController animated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionReveal:{
            [self coreAnimationWithController:viewController duration:.5 type:kCATransitionReveal subtype:subtype
                                 changesBlock:^{
                                     [self pushViewController:viewController animated:NO];
                                 }];
            break;}
        default:{
            break;}
    }
}

#pragma mark -
#pragma mark popping

- (void)popViewControllerWithCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype {
    switch (transition) {
        case CustomViewAnimationTransitionNone:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionNone
                                     changesBlock:^{
                                         [self popViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFlipFromLeft:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionFlipFromLeft
                                     changesBlock:^{
                                         [self popViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFlipFromRight:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionFlipFromRight
                                     changesBlock:^{
                                         [self popViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionCurlUp:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionCurlUp
                                     changesBlock:^{
                                         [self popViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionCurlDown:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionCurlDown
                                     changesBlock:^{
                                         [self popViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFadeIn:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionFade subtype:nil
                                 changesBlock:^{
                                     [self popViewControllerAnimated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionMoveIn:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionMoveIn subtype:subtype
                                 changesBlock:^{
                                     [self popViewControllerAnimated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionPush:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionPush subtype:subtype
                                 changesBlock:^{
                                     [self popViewControllerAnimated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionReveal:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionReveal subtype:subtype
                                 changesBlock:^{
                                     [self popViewControllerAnimated:NO];
                                 }];
            break;}
        default:{
            break;}
    }
}

- (void)popToRootViewControllerWithCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype {
    switch (transition) {
        case CustomViewAnimationTransitionNone:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionNone
                                     changesBlock:^{
                                         [self popToRootViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFlipFromLeft:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionFlipFromLeft
                                     changesBlock:^{
                                         [self popToRootViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFlipFromRight:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionFlipFromRight
                                     changesBlock:^{
                                         [self popToRootViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionCurlUp:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionCurlUp
                                     changesBlock:^{
                                         [self popToRootViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionCurlDown:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionCurlDown
                                     changesBlock:^{
                                         [self popToRootViewControllerAnimated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFadeIn:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionFade subtype:nil
                                 changesBlock:^{
                                     [self popToRootViewControllerAnimated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionMoveIn:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionMoveIn subtype:subtype
                                 changesBlock:^{
                                     [self popToRootViewControllerAnimated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionPush:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionPush subtype:subtype
                                 changesBlock:^{
                                     [self popToRootViewControllerAnimated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionReveal:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionReveal subtype:subtype
                                 changesBlock:^{
                                     [self popToRootViewControllerAnimated:NO];
                                 }];
            break;}
        default:{
            break;}
    }    
}

- (void)popToViewController:(UIViewController *)viewController withCustomTransition:(CustomViewAnimationTransition)transition subtype:(NSString*)subtype {
    switch (transition) {
        case CustomViewAnimationTransitionNone:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionNone
                                     changesBlock:^{
                                         [self popToViewController:viewController animated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFlipFromLeft:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionFlipFromLeft
                                     changesBlock:^{
                                         [self popToViewController:viewController animated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFlipFromRight:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionFlipFromRight
                                     changesBlock:^{
                                         [self popToViewController:viewController animated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionCurlUp:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionCurlUp
                                     changesBlock:^{
                                         [self popToViewController:viewController animated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionCurlDown:{
            [self standardAnimationWithController:nil duration:.5 options:UIViewAnimationOptionTransitionCurlDown
                                     changesBlock:^{
                                         [self popToViewController:viewController animated:NO];
                                     }];
            break;}
        case CustomViewAnimationTransitionFadeIn:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionFade subtype:nil
                                 changesBlock:^{
                                     [self popToViewController:viewController animated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionMoveIn:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionMoveIn subtype:subtype
                                 changesBlock:^{
                                     [self popToViewController:viewController animated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionPush:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionPush subtype:subtype
                                 changesBlock:^{
                                     [self popToViewController:viewController animated:NO];
                                 }];
            break;}
        case CustomViewAnimationTransitionReveal:{
            [self coreAnimationWithController:nil duration:.5 type:kCATransitionReveal subtype:subtype
                                 changesBlock:^{
                                     [self popToViewController:viewController animated:NO];
                                 }];
            break;}
        default:{
            break;}
    }        
}

#pragma mark -
#pragma mark private

- (void)standardAnimationWithController:(UIViewController*)viewController
                                duration:(NSTimeInterval)duration
                                options:(UIViewAnimationOptions)options
                                changesBlock:(void (^)(void))block {
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:duration];
    [UIView transitionWithView:self.view duration:duration options:options animations:block completion:NULL];
    [UIView commitAnimations];
}

- (void)coreAnimationWithController:(UIViewController*)viewController
                                duration:(NSTimeInterval)duration
                                type:(NSString*)type
                                subtype:(NSString*)subtype
                                changesBlock:(void (^)(void))block {
    CATransition* trans = [CATransition animation];
    [trans setDuration:duration];
    [trans setType:type];
    [trans setSubtype:subtype];
    [self.view.layer addAnimation:trans forKey:kCATransition];
    block();
}

@end

【讨论】:

  • 哦!我应该将它包含到我的自定义 NavigationController 中吗?
  • 不,只需将此代码粘贴到类别文件中(.h 用于接口,.m 用于实现)并确保它们在您的项目中可用。然后将头文件导入您要使用类别方法的任何位置。如果您无法理解类别的工作原理,请参阅here
  • 我把代码一分为二,第一部分粘贴到头部,第二部分粘贴到实现文件中。
  • 我是按照你说的方式做的。可能是其他一些原因造成的问题
  • 你真的在你调用[self.navigationController pushViewController:places withCustomTransition:CustomViewAnimationTransitionPush subtype:CustomViewAnimationSubtypeFromLeft];的文件中导入UINavigationController+Additions.h吗?
【解决方案2】:

您需要将QuartzCore.framework 添加到您的目标以解决_OBJC_CLASS_$_CATransition 错误。

【讨论】:

    【解决方案3】:

    我最近着手创建自己的过渡,这是我制作的可重用库:

    https://github.com/travisjeffery/TRVSNavigationControllerTransition

    这是我的blog post 谈论如何进行自己的过渡。

    基本的想法很简单,只需对 navigationController(当前)视图进行 CALayer 快照,然后在没有动画的情况下推送/弹出视图,获取新视图的 CALayer 快照,然后将您自己的动画添加到这些视图中层,然后在动画完成后移除这些层。

    【讨论】:

    • 拍摄快照会严重延迟过渡。尤其是在旧设备上。