前言
平常咱们运用的 push
、pop
、present
、dismiss
动画,无非便是体系默许的推动、推出作用,model
动画还好点,有四种
作用,navigation
就只有一种
作用了
假如想要运用合适场景的自定义动画,那么就需求自定义了,例如:微信的查看大图,一些改换特效等
案例demo
自定义转场动画
model转场动画特有协议
model
转场动画,也便是常见的 present
、dismiss
,设置其转场动画要完结下面两个特有的办法
留意:其应当是一个转场动画一个 UIViewControllerAnimatedTransitioning
完结类(后边介绍),demo
为了便利,提取出来了一个共用类,所以略有不同
//present动画的设置办法
//回来完结 UIViewControllerAnimatedTransitioning 协议的目标(后边介绍)
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source;
//dissmiss动画的设置办法
//回来完结 UIViewControllerAnimatedTransitioning 协议的目标(后边介绍)
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
navigation转场动画特有协议
navigation
转场动画,也便是常见的 push
、pop
,设置其转场动画要完结下面两个特有的办法
留意:其应当是一个转场动画一个 UIViewControllerAnimatedTransitioning
完结类(后边介绍),demo
为了便利,提取出来了一个共用类,所以略有不同
//push、pop共用的一个动画设置办法
//回来完结 UIViewControllerAnimatedTransitioning 协议的目标(后边介绍)
//动画的类型(push、pop)可经过operation枚举类型来区分,能够看下面枚举
//能够依据需动画要运用
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC;
operation如下所示,为一个转场动画的操作类型,一般为push
或pop
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的动画了,能够应用到 mode
和navigation
中,信任看到了也觉得很简略,下面循序,继续介绍
完结了 UIViewControllerContextTransitioning
协议的 transitionContext
有哪些常用办法呢
containerView
: 当时展示的底部视图,需求将改换后的图层(ToViewController
)增加上去,不然不显现当时控制器图层,在改换图层的过程中,能够经过增加和移除新图层,来完结杂乱一些的过渡动画
completeTransition:
: 完结动画后,标记改换完毕,以完善该流程的体系的其他处理
viewControllerForKey:
: 经过 transitionContext
参数,能够经过该办法,加上一些key来获取 fromViewController
和toViewController
,即push、pop等前后两个视图控制器,一共有两个key:UITransitionContextFromViewControllerKey
、UITransitionContextToViewControllerKey
,信任看姓名就知道表达的含义,分别为改换前后的控制器 from -> to
viewForKey:
: 与 viewControllerForKey
类似,获取控制器视图的参数,回来 UIView类型的参数,分别为:UITransitionContextFromViewKey
、UITransitionContextToViewKey
,分别为改换前后的控制器内部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、获取控转场动画改换前后的视图控制器 fromViewController
、toViewController
2、将 toViewControlle
r 的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与手势的一些问题
快来测验一些自定义转场动画吧,无妨做一个仿微信的图片扩大作用吧