一行代码实现自定义转场动画

前言

系统自带的presentViewControllerpushViewController已经能够很好的完成场景与场景之间的过渡了,而且提供的动画视觉效果也很简洁流畅,称之为iOS系统的标志之一也不为过。
但是如果能让转场过程根据业务情景做一些更丰富,或者说是更适合的动态表现,其实也不失为一种内容表达上的点睛之笔。

通过拜读两位大神:KittenYang、 OneV's Den的系列文章,逐渐尝试、总结,输出了这套专注于自定义转场动画的工具:XTTransitionAnimations。
这里不再赘述转场动画的实现原理,有需要的小伙伴可以到两位大神的文章学习下~ 也欢迎留言讨论~

实现功能

一行代码实现自定义转场动画
[self XT_PresentViewController:vc animatedType:XTSpringFromBottom interact:NO completion:nil];

[self.navigationController XT_PushViewController:vc animatedType:XTRoundExpand interact:YES];
  • 与系统原生的present和push转场api极其相似,学习成本低;
  • 支持动画效果参数配置,如时长,阻尼系数,弹性曲线等;
  • 可配置转场动画是否可交互;
  • 侵入性很低,不对UI层干涉;
  • 默认生成配套的dismiss/pop动画,也可单独配置;
  • 可交互动画中,弹性动画与线性动画自动切换。

工具目前内置四类自定义动画(后续会继续拓展),使用时通过枚举类型参数设置即可;目前主要实现的动画效果有以下四类:


Spring From Bottom(present,interact,XTSpringFromEdgeAnimation)

Spring From Right(push,interact,XTSpringFromEdgeAnimation)

Round Spring Expand(present,interact,XTRoundExpandAnimation)

Card Spring From Bottom(present,interact,XTCardPresentAnimation)

Cube Rotate From Right(push,interact,XTCubeAnimation)

Cube Rotate From Top(present,interact,XTCubeAnimation)
只需实现动画对象就可以自定义你自己的转场动画

工具支持动画种类扩展。主要流程如下:

  1. 生成一个实现你想要的效果的服从UIViewControllerAnimatedTransitioning协议的动画对象(例如Animations文件夹中的类);
  2. (可选)如果手势滑动距离控制转场动画进度的交互方式并不能满足你的需求,可以生成一个继承于XTBaseInteractiveObj的子类,来定制交互方式(例如Interactive文件夹中的类);
  3. 完成XTAnimationsConfig.plist中动画的基本配置;
  4. 最后维护convertAnimationTypeEnumToStr:方法(将枚举类型转换为字符串)。

即可使用工具统一的api完成自定义转场动画的使用。

解释一下XTAnimationsConfig.plist的用处:

除了之前说的阻尼系数等非普适性参数(不是每个动画都需要的参数),对于一些所有动画都需要的基本参数,例如,实现类,实现交互的类,交互完成的标志等等,就是通过XTAnimationsConfig.plist来配置的。 其中有多个字典,每个字典对应一个动画类型(XTAnimationType)。下面具体来介绍一下,其中各键的意义:

  • animationClass:实现该动画需要的类的类名(Animations文件夹中的各个类);
  • interactiveClass:实现交互所需的配置;
    • className:该动画实现交互所需的类的类名(Interactive文件夹中的各个类);
    • isVertical:由于一般的交互是通过手势控制的,而且大多与手势的移动距离有关,因此该属性配置当前交互的进度是与竖直方向还是水平方向的位移有关;
    • isAccordToCoordinate:动画完成进度的变化趋势是否与屏幕的坐标体系一致,即位移为正值逐渐变大时,是否完成进度也在逐渐变大;
    • completePointNum:动画完成所需要位移的点数;
      • ScreenHorW:点数是基于屏幕的高还是宽来计算(W:宽;H:高);
      • percent:点数占屏幕宽或高的百分比;(通过以上两个参数计算完成过场动画所需的位移点数)
      • absolutePointNum:输入具体的点数,位移距离达到指定点数则当前动画达到完成条件(优先于以上两个参数生效)

使用方法

引入头文件

#import "UIViewController+XTTransitionAnimations.h"
#import "UINavigationController+XTTransitionAnimations.h"
Present
/**
 根据animatedType定制present时的转场动画,默认dismiss返回时有配套的转场动画。

 @param viewControllerToPresent 弹出的VC
 @param aniType 动画种类
 @param isInteract 转场动画是否可交互
 @param completion 完成动画时的回调
 */
-(void)XT_PresentViewController:(UIViewController *)viewControllerToPresent animatedType:(XTAnimationType)aniType interact:(BOOL)isInteract completion:(void (^)(void))completion;
定制Dismiss
/**
 如果不想使用present配套的转场动画 或 只需要dismiss时出现转场动画,可使用该方法单独定制dismiss时的转场动画。
(1.建议在需要dismiss的VC初始化完成后,视图展示之前,例如viewWillAppear中调用该方法完成配置,否则会出现交互部分仍按XT_PresentViewController中设置的配套动画执行的情况;
 2.不建议某些关联性较强的present和dismiss动画,例如XTCardSpringFromBottom等,使用此方法定制动画,视觉效果会很差;
 3.在正确位置调用该方法完成配置后,需要dismiss时直接调用系统的popViewControllerAnimated:方法即可。)
 
 @param aniType 动画种类
 @param isInteract 转场动画是否可交互
 */
-(void)XT_ConfigureDismissWithAnimatedType:(XTAnimationType)aniType interact:(BOOL)isInteract;
Push
/**
 根据animatedType定制push时的转场动画,默认pop返回时有配套的转场动画。

 @param viewController push到的VC
 @param aniType 动画种类
 @param isInteract 转场动画是否可交互
 */
-(void)XT_PushViewController:(UIViewController *)viewController animatedType:(XTAnimationType)aniType interact:(BOOL)isInteract;

以上就是这套工具的大致介绍,希望大家多多指正、讨论!
如果觉得对你有一点用的话,也希望你能动动你的小手,来个赞啊、star啊什么的~
如果有小伙伴觉得这套框架的思路还行,更希望大家一起来实现更多的动画效果!

Github地址


看啊!这里有个坑!

这里主要就是分享在写转场动画过程中遇到的坑。

  1. layer层的全部动画,类似于
[xxLayer addAnimation:pathAni forKey:[NSString stringWithFormat:@"%@",self.class]];)

的这种动画,在iOS11中,对进度的控制全部无效!也就是说,在继承于UIPercentDrivenInteractiveTransition的负责交互的对象中,使用updateInteractiveTransition:来更新动画进度,是不生效的,动画只要一开始,就正常执行一直到结束,丝毫不受传入的进度参数影响。同样代码,在iOS10中测试,是没有问题的。
而且,即使在iOS10中,在交互过程中,如果交互程度没有超过交互完成点,最后通过cancelInteractiveTransition取消了交互,view层的动画,可以让动画按照“原路”返回初始状态,但layer层动画并不能,直接瞬间填充;超过结束完成点,但还有部分可视内容时,也直接瞬间消失,而不是像view动画那样继续动画到最终完成状态。
通过查阅资料,在iOS11中,系统对view的动画进行了相当多的扩展,所以,我很大胆的猜想了一下,是不是Apple在引导开发者向view动画进行倾斜呢?但就算真是这样,也不应该直接就悄无声息的改掉啊?没有任何书面的说明?
希望有大神能够批评指正。
因此,在iOS11中,工具中的XTRoundExpandAnimation动画类型,暂时不支持交互。。。(日后会争取实现非layer动画的实现方式)

  1. 动画完成后,一定要还原view的所有形变。实现转场动画时,可能会对view的某些参数,例如anchorPoint、position等影响布局的参数进行修改,因此,如果在动画完成后,如果不将其还原的话,会影响之后view上的UI展示层效果;而且,当自定义的转场动画,相互叠加时,例如present一个navVC,navVC中再相互push,最后再其中某一个dismiss,那么影响将更明显。

  2. 在动画对象的- (void)animateTransition:(id )transitionContext方法中实现动画时,一定要使用根据transitionContext生产的frame等参数,不要使用屏幕大小等方式来获取,不然的话在稍微复杂一点的动画中,就会出现无法准确获得view的关键节点状态值的情况,造成动画效果达不到预期。

  3. 在Present的转场过程中,还有一个利器,就是UIPresentationController。个人认为,他是iOS8.0中出现的一个对animationControllerForPresentedControlleranimationControllerForDismissedController进行简易封装的api,而且监控的粒度更细。大多数人都是将他与animationControllerForPresentedControlleranimationControllerForDismissedController结合着进行使用,但是个人认为,他也可以独立完成Present转场动画的实现,而且这样与Push转场动画的实现逻辑很相似。但是,他无法独立完成动画的交互实现。
    如果真的要结合在一起使用的话,注意其和animationControllerForPresented/DismissedController之间对视图的作用是同时生效的,因此要注意各司其职,不要出现反复添加、处理视图之类的问题。

你可能感兴趣的:(一行代码实现自定义转场动画)