iOS自定义转场动画

在iOS程序里出现得最多的转场动画,就是UINavigationController的Push和Pop了,看多了就觉得有些无聊了,还好苹果提供了自定义转场动画的API,往下看。

首页,要明白既然转场动画是通过导航控制器来完成(UIViewController模态除外),那么就往UINavigationController看,既然是转场,那么在两个控制器切换的中间,就是转场动画发生的地方,一提到“将要出现”,“已经出现”,“将要消失”,“已经消失”,条件反射就想到了UINavigationController的代理方法:

@protocol UINavigationControllerDelegate <NSObject>

@optional

// Called when the navigation controller shows a new top view controller via a push, pop or setting of the view controller stack.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

- (NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);
- (UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController *)navigationController NS_AVAILABLE_IOS(7_0);

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);

- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);

@end

注意最后两个方法,就是它了,注意可用的iOS版本: NS_AVAILABLE_IOS ( 7 _0)

- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);
这个方法是讲的手势百分比交互,今天不谈,说最后一个方法,它的返回值是

id <UIViewControllerAnimatedTransitioning>,一个遵循UIViewControllerAnimatedTransitioning的对象,点开它:

@protocol UIViewControllerAnimatedTransitioning <NSObject>

// This is used for percent driven interactive transitions, as well as for container controllers that have companion animations that might need to
// synchronize with the main animation. 
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext;
// This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;


@optional
两个方法,第一个是返回动画持续时间,第二个是动画具体内容。

说了这么多理论,总结一下自定义转场动画大致的设置思路:

1、自定义一个继承自NSObject并且遵从UIViewControllerAnimatedTransitioning协议的类,里面实现协议方法,设置好动画时长和具体内容;

2、在转场动画发生的viewcontroller里,遵从UINavigationControllerDelegate协议,实现协议方法

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
在该方法里返回自定义的动画类的一个对象即可。

示例:



新建一个有两个viewcontroller的工程:FirstViewController、SecondViewcontroller,将FirstViewcontroller加到一个导航控制器里,它的view上有一个“push”按钮,点它可以将SecondViewController push进来,SecondViewController上有一个“pop”按钮,点它可以pop到FirstViewController,描述得已经很清楚了吧。

创建两个继承自NSObject的类,一个叫PushAnimation,一个叫PopAnimation,它们都遵循UIViewControllerAnimatedTransitioning协议:

@interface PushAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end

@interface PopAnimation : NSObject<UIViewControllerAnimatedTransitioning>

@end

在PushAnimation.h
//返回动画持续时间
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 2.0f;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    //获取起点controller
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    
    //获取终点controller
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    //获取转场容器视图
    UIView *containerView = [transitionContext containerView];
    
    //设置终点视图的frame
    CGRect frame = [transitionContext initialFrameForViewController:fromVC];
    CGRect offScreenFrame = frame;
    //先将其设置到屏幕外边,通过动画进入
    offScreenFrame.origin.x = offScreenFrame.size.width;
    toVC.view.frame = offScreenFrame;
    
    //添加视图
    [containerView addSubview:toVC.view];
    
    //执行动画
    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        //设置缩放和透明度
        fromVC.view.transform = CGAffineTransformMakeScale(0.8, 0.8);
        fromVC.view.alpha = 0.5;
        //设置位置
        toVC.view.frame = frame;
    } completion:^(BOOL finished) {
        fromVC.view.transform = CGAffineTransformIdentity;
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
}

在PopAnimation里实现下面方法(push的逆动画,其实可以只创建一个类,通过“顺”or“逆”来判断执行的动画):

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return 2.0f;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    UIView *containerView = [transitionContext containerView];
    
    toVC.view.transform = CGAffineTransformMakeScale(0.8, 0.8);
    toVC.view.alpha = 0.5;
    CGRect frame = [transitionContext initialFrameForViewController:fromVC];
    CGRect offScreenFrame = frame;
    offScreenFrame.origin.x = offScreenFrame.size.width;
    
    [containerView insertSubview:toVC.view belowSubview:fromVC.view];
    
    
    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        toVC.view.transform = CGAffineTransformIdentity;
        toVC.view.alpha = 1.0f;
        fromVC.view.frame = offScreenFrame;
    } completion:^(BOOL finished) {
        fromVC.view.transform = CGAffineTransformIdentity;
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

在FirstViewController.m里添加下面代码:

#import "PushAnimation.h"

@interface FirstViewController ()<UINavigationControllerDelegate>
{
    PushAnimation *_pushAni;
}
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    _pushAni = [PushAnimation new];
}

- (void)viewDidAppear:(BOOL)animated
{
    self.navigationController.delegate = self;
    [super viewDidAppear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
    [super viewDidDisappear:animated];
}

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

同样,在SecondViewController里设置pop的动画代码,即可,更好的方法,可以写一个继承自UINavigationController的子类,统一实现协议方法。






  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值