前言

平常咱们运用的 pushpoppresentdismiss动画,无非便是体系默许的推动、推出作用,model动画还好点,有四种作用,navigation就只有一种作用了

假如想要运用合适场景的自定义动画,那么就需求自定义了,例如:微信的查看大图,一些改换特效等

案例demo

自定义转场动画

model转场动画特有协议

model转场动画,也便是常见的 presentdismiss,设置其转场动画要完结下面两个特有的办法

留意:其应当是一个转场动画一个 UIViewControllerAnimatedTransitioning完结类(后边介绍),demo为了便利,提取出来了一个共用类,所以略有不同

//present动画的设置办法
//回来完结 UIViewControllerAnimatedTransitioning 协议的目标(后边介绍)
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented 
    presentingController:(UIViewController *)presenting 
    sourceController:(UIViewController *)source;
//dissmiss动画的设置办法
//回来完结 UIViewControllerAnimatedTransitioning 协议的目标(后边介绍)
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;

navigation转场动画特有协议

navigation转场动画,也便是常见的 pushpop,设置其转场动画要完结下面两个特有的办法

留意:其应当是一个转场动画一个 UIViewControllerAnimatedTransitioning完结类(后边介绍),demo为了便利,提取出来了一个共用类,所以略有不同

//push、pop共用的一个动画设置办法
//回来完结 UIViewControllerAnimatedTransitioning 协议的目标(后边介绍)
//动画的类型(push、pop)可经过operation枚举类型来区分,能够看下面枚举
//能够依据需动画要运用
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController 
    animationControllerForOperation:(UINavigationControllerOperation)operation 
    fromViewController:(UIViewController *)fromVC 
    toViewController:(UIViewController *)toVC;

operation如下所示,为一个转场动画的操作类型,一般为pushpop

typedef NS_ENUM(NSInteger, UINavigationControllerOperation) {
  UINavigationControllerOperationNone,
  UINavigationControllerOperationPush,
  UINavigationControllerOperationPop,
};

通用转场动画协议(UIViewControllerAnimatedTransitioning)

自定义转场动画要完结的核心协议便是UIViewControllerAnimatedTransitioning,不管是 mode仍是navigation都要完结此协议,其常常运用的办法有下面两个:

//设置动画执行时间
- (NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)
transitionContext;
//自定义动画的完结办法,transitionContext里边有完结动画所需求的相关变量
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext

设置动画时间的不说,animateTransition:才是咱们编写转场动画的办法,下面先给一个案例,然后再介绍一下里边的其他属性

- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
    //获取变化前的控制器,push前的顶部控制器(pop相反)
    UIViewController *fromVc = [transitionContext 
        viewControllerForKey:UITransitionContextFromViewControllerKey];
    //获取变化后的控制器,push后的顶部控制器(pop相反)
    UIViewController *toVc = [transitionContext 
        viewControllerForKey:UITransitionContextToViewControllerKey];
    //用与改换的containerView,也是最底部的view,需求主动增加toVc.view到上面去
    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:toVc.view];
    //选用UIView动画改换图层
    [UIView 
        transitionFromView:fromVc.view 
        toView:toVc.view 
        duration:[self transitionDuration:transitionContext] 
        options:UIViewAnimationOptionTransitionFlipFromLeft 
        completion:^(BOOL finished) {
        //完结过渡动画后,标记改换完毕
        [transitionContext completeTransition:YES];
    }];
}

上面便是一个 Flip的动画了,能够应用到 modenavigation中,信任看到了也觉得很简略,下面循序,继续介绍

完结了 UIViewControllerContextTransitioning协议的 transitionContext有哪些常用办法呢

containerView: 当时展示的底部视图,需求将改换后的图层(ToViewController)增加上去,不然不显现当时控制器图层,在改换图层的过程中,能够经过增加和移除新图层,来完结杂乱一些的过渡动画

completeTransition:: 完结动画后,标记改换完毕,以完善该流程的体系的其他处理

viewControllerForKey:: 经过 transitionContext参数,能够经过该办法,加上一些key来获取 fromViewControllertoViewController,即push、pop等前后两个视图控制器,一共有两个key:UITransitionContextFromViewControllerKeyUITransitionContextToViewControllerKey,信任看姓名就知道表达的含义,分别为改换前后的控制器 from -> to

viewForKey:: 与 viewControllerForKey类似,获取控制器视图的参数,回来 UIView类型的参数,分别为:UITransitionContextFromViewKeyUITransitionContextToViewKey,分别为改换前后的控制器内部view

initialFrameForViewController、finalFrameForViewController: 用于参阅的两个参数,为控制器改换前后的 frame 信息,用于作为动画参阅,或许动画处理时运用

animationEnded:push、pop是否应用了动画,用于动画控制,能够不运用该参数

前面介绍了containerView是展示界面UI底部视图,在进行动画时,咱们需求将 toViewController的view视图增加上去,这样新页面才会正常显现

因此咱们在 containerView上面增加的视图不会消失,在进行动画处理的时候需求留意

containerView与截图大法 snapshotViewAfterScreenUpdates:结合运用能够制造比较杂乱的动画作用,可是使原图层免受动画改换的搅扰

//能够将指定图截图绘制成生成一个新的View图层,可用于动画图层改换显现
//能够了解为一张 imageView 图片
UIView *fromView = [fromVc.view snapshotViewAfterScreenUpdates:YES];
UIView *toView = [toVc.view snapshotViewAfterScreenUpdates:YES];

经过上面 snapshotViewAfterScreenUpdates 办法生成的 view,当做改换图层时运用的暂时view改换,以用来制造杂乱动画,而不影响真实的 viewController图层

截图大法制造动画原理:能够了解在真实的原始图层上面,加上一个如出一辙的图层,对上面的图层各种改换,最后改换成和在原始图层相同的款式,随后瞬间移除,这样用户看到的作用就和改换原始真实图层作用相同了

下面是运用截图大法制造的一个类似 push的推动作用,从截图那一步开端,其实就算是为了动画做准备了

别的,假如杂乱动画用到了 CoreAnimation 相关 api,能够运用其署理,来合理监听动画的开端和完毕

UIViewController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//用与改换的containerView,也是最底部的view,需求主动增加toVc.view到上面去
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toVc.view];
//依据原始图层生成新的截图,以便于过渡动画的制造
UIView *fromView = [fromVc.view snapshotViewAfterScreenUpdates:YES];
UIView *toView = [toVc.view snapshotViewAfterScreenUpdates:YES];
//获取视图宽高,能够运用finalFrameForViewControllerc等获取frame来处理,这儿为了便利就直接运用了
CGFloat width = fromView.frame.size.width;
CGFloat height = fromView.frame.size.height;
//设置动画过渡前的 viewframe 状况,能够缩放(rotation),渐变(alpha)
fromView.frame = CGRectMake(0, 0, width, height);
toView.frame = CGRectMake(-width, 0, width, height);
//将截图取得过渡动画图层,增加到 containerView上面,以显现过渡动画
[containerView addSubview:fromView];
[containerView addSubview:toView];
//开端过渡动画
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
    fromView.frame = CGRectMake(width, 0, width, height);
    toView.frame = CGRectMake(0, 0, width, height);
} completion:^(BOOL finished) {
    //过渡动画完毕后,移除后增加的两个过渡动画图层view
    [fromView removeFromSuperview];
    [toView removeFromSuperview];
    [transitionContext completeTransition:YES];
}];
//运用animation的时候需求设置署理,这样就能够得到动画开端完毕的机遇了
//  CABasicAnimation *basic;
//  basic.delegate = self;
//  - (void)animationDidStart:(CAAnimation *)anim;
//  - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

经过能够看到运用截图大法,大致经过了下面 3 步:

1、获取控转场动画改换前后的视图控制器 fromViewControllertoViewController

2、将 toViewController 的view增加到 containerView上面,以显现改换后的控制器图层,到这儿,假如没有动画,能够了解为已经完毕了(只需求在调用completeTransition即可)

3、这儿咱们便是开端动画的制造了,简略的动画,能够直接运用原图层进行改换操作即可,杂乱的能够运用截图大法来做

3.1 普通动画制造,运用的前提是不会对原始图层搅扰,直接运用原始图层,直接运用体系的动画办法进行改换,动画完毕后,运用completeTransition 标记改换完毕

3.2 杂乱动画制造,万金油,不管对原始图层搅扰与否,都能够运用,仅仅逻辑上稍微杂乱一些,越杂乱的动画处理起来逻辑越多

3.2.1 杂乱动画第一步,先进行截图处理,运用 snapshotViewAfterScreenUpdates办法,获取新的图层,然后增加到 containerView上面

3.2.2 在设置动画之前款式,假如是平移推动,那么就处理好方位;假如是缩放,那么就提早设置好缩放的点以及倍率,开端之前的款式,必定要和 fromViewContoller的原始款式相同

3.2.3 设置动画过渡之后的款式,其过渡之后的款式相同要为 toViewController的原始款式,不管方位仍是大小等,都要相同(假如过渡动画比较麻烦,或许中间要分为好几步骤,不管怎样,开端和完毕的款式都要与原始款式相同)

3.2.4 过渡动画完结之后,需求移除后增加到 containerView上面的复制图层,然后调用 completeTransition 标记改换完毕

最后

对于pop上一页的手势问题,能够参阅上一篇文章:navigation与手势的一些问题

快来测验一些自定义转场动画吧,无妨做一个仿微信的图片扩大作用吧