CoreAnimation解析及中高级动画实现

一.CoreAnimation介绍

CoreAnimation是一套图像渲染和动画基础框架,其在iOS和OSX平台用于显示对象和实现动画效果。使用CoreAnimation框架,动画的大部分帧渲染都是苹果为咱们作好的。咱们只须要配置几个动画参数(如开始和结束的点)并调用动画开始的方法。接下来就把剩余的工做交给CoreAnimation,操做所有实际绘图工做是在图形渲染硬件加速处理的。这个自动的图像加速器将会产生高帧频和顺滑的动画效果而不会加剧CPU的负荷、或使APP卡顿。
html

CoreAnimation是在UIKit和APPKit框架之下,而且被很好的整合到Cocoa和Cocoa Touch的view中。同时CoreAnimation也给出了一些扩展的动画接口供咱们使用。git

下图是CoreAnimation在cocoa框架中的层级(图片来自苹果)github


CoreAnimation

苹果对于CoreAnimation的介绍中首先讲述的是CALayer,由于CALayer是视图显示的基础、同时是CAAnimation动画产生的的载体。全部的动画都是做用在CALayer上,经过更改CALayer的属性,将每一帧渲染出来就造成了咱们视觉的动画效果。可是这篇博客主要介绍CAAnimation,因此直接先忽略了前面的CALayer介绍,关于CALayer会在下一篇的文章中作详细介绍。
数组

二.CoreAnimation动画

上面已经说过了,CoreAnimation是一套图形渲染与动画框架,CALayer负责图形的渲染显示,而CAAnimation及其子类则负责动画的实现。经过CAAnimatin及其子类咱们可以相对简单的实现一些复杂的layer动画。并发

下面是整个CoreAnimation框架的全部动画类结构:app


动画类结构

1.动画

CAAnimationCoreAnimation的抽象超类、而CAPropertyAnimation又是CAAnimation的抽象子类,正如咱们所知道的咱们不该该直接使用抽象类,而应该使用它们的子类,如CABasicAnimation(基础动画)、CAKeyFrameAnimation(关键帧动画)、CASpringAnimation(弹簧动画)等。框架

1.1 CAAnimation

CAAnimationCoreAnimation的抽象超类,也是整个动画的核心类,大部分的动画属性与方法都是在该类中实现的。CAAnimation之因此可以拥有这些动画相关的属性和方法是由于该类遵照了CAMediaTiming CAAction两个协议。CAMediaTiming协议主要实现一些控制动画执行时间的属性和函数(包含动画的开始时间 -> beginTime、执行时间 -> duration、执行速率 -> speed、执行时间偏移量 -> timeOffset、重复执行的次数 -> repeatCount、动画执行结束的处理 ->filleMode等),所以CAAnimation可以很好的处理时间与layer动画的关系;CAAction主要实现一些动做触发的响应接口,遵照该协议的对象能够指定CALayer响应的行为,如添加一个动画效果,或者执行其余的tasks。ide

timingFunction:属性用于设置动画执行的时间步调,建立该对象相对简单,能够直接使用kCAMediaTimingFunction系列宏指定动画执行的时间为`linear', `easeIn', `easeOut' and `easeInEaseOut'或者也可使用贝塞尔曲线函数建立一个CAMediaTimingFunction对象贝塞尔曲线控制点获取函数

delegate:设置Animation的代理对象,这样咱们能够获取动画执行过程的一些状态,包括动画的开始和结束,若是你只是想在结束时得到回调通知,也能够调用setCompletionBlock:函数,设置动画完成的block回调。oop

removedOnCompletion:动画执行结束是否移除动画,默认YES,可是该参数必须与fillMode = kCAFillModeForwards 或者 kCAFillModeBoth同时设置才能实如今动画结束不移除动画layer。

1.2 CAPropertyAnimation

CAPropertyAnimationCAAnimation的抽象子类,使用该类能够建立一个操做CALayer属性值的Animation对象。该类主要实现接口用于指定实现动画的CALayer的属性。

1.3 CABasicAnimation

CABasicAnimationCAPropertyAnimation的子类,该类实现了三个属性fromValue、byValue、toValue、用于描述一个单关键帧动画执行过程的三个属性值。

1.4 CAKeyFrameAnimation

CAKeyFrameAnimationCAPropertyAnimation的子类,该类用于实现多关键帧动画。咱们能够将动画主要的一些帧值添加到数组,赋值给values属性,再把每一帧对应的时间添加到keyTimes属性,(值得注意的是keyTimes的值必须在【0,1】之间,数组中的值按照数组的index依次增大,而且全部值加在一块儿的和等于一),若是想要为每一帧指定一个CAMediaTimingFunction对象,也能够建立对应的CAMediaTimingFunction对象并加到数组,而后赋值给timingFunctions属性。

CAKeyFrameAnimation最强大的地方在于他有一个path属性,当咱们建立一个路径并赋值给path属性时,动画就会按照咱们指定的路径轨迹执行。

1.5 CASpringAnimation

CASpringAnimation继承于CABasicAnimation类,正如它的名字Spring同样,该类主要用于实现一些相似弹簧的动画效果。mass属性至关于物体的重量,stiffness属性表明了弹簧的刚度,damping属性表明阻尼系数,initialVelocity属性表明动画的初始速度,settlingDuration是动画的预估执行时间。经过这些属性值,咱们能够控制Spring动画的拉伸幅度,动画的执行时间等。

2.组动画

在动画使用的过程当中,咱们通常不会只使用一个动画,咱们可能为复杂的动画效果建立多个Animation对象,而后将这些对象分别添加到Layer动画中,这种方式可以实现可是相对比较麻烦,咱们可使用组动画解决这个问题。 对于组合动画咱们可使用CATransition()和CAAnimationGroup, CAAnimationGroup将多个动画合并为一组,而且咱们能够指定动画关联时间让组内的动画能够同时或者按步骤执行,CATransaction将多个layer-tree更改操做放在一块儿执行并自动更新到render tree。

2.1 CAAnimationGroup

CAAnimationGroupCAAnimation的子类,该动画将多个动画放到一个animations数组,添加到layer,这些动画是并行执行的,固然你也能够设置例如beginTime这样的属性使动画按照必定的顺序执行。

2.2CATransition()

CATransition继承于CAAnimation,该动画主要实现一些过渡效果。你能够为type属性设置`fade', `moveIn', `push' and `reveal'来实现你想要的动画效果,同时你也能够设置subtype为`fromLeft', `fromRight', `fromTop' and`fromBottom'来指定动画的方向。startProgressendProgress用于控制开始和结束的进度,范围必须在【0,1】。

3.动画执行时间

时间是动画的重要部分之一,咱们能够经过CAMediaTiming协议的方法和属性指定动画的时间信息。在CoreAnimation中遵照这个协议的有两个类。CAAnimation类采用了这个协议,所以能够为Animations执行指定时间信息。CALayer类也采用了该协议,所以也能够为隐式动画指定Animations执行相关的时间信息,值得注意的是隐式动画优先采用默认的时间信息。

想一想时间和动画的关系,理解layer对象是如何和时间相互做用的是很是重要的。每个layer对象都有一个本地的时间去管理动画时间。一般在动画过程当中的两个layer的本地时间很是接近,接近到咱们可能察觉不到有什么不一样。本地时间能够被父layer或者本身拥有的timing参数更改

CALayer类定义了convertTime:fromLayer: convertTime:toLayer:方法,为了确保时间值适用于layer。咱们可使用这些方法将layer的时间值转换为相对于本地时间或者另外一个layer时间值的精确时间。使用这些方法须要考虑到对layer的本地时间的影响,同时这些方法会返回一个能够在其余的layer中使用的值。

一旦咱们有了一个layer的本地时间值,咱们就可使用这个值去更新Animation对象或者layer的相关属性,使用CAMediaTiming协议属性,咱们能够实现一些有趣的动画效果,包括:

1.咱们可使用beginTime属性设置Animation的开始时间。一般状况,Animations的开始时间是在下一次更新循环(the next update cycle),可是咱们能够设置beginTime参数来延迟动画的执行时间。咱们能够设置后一个动画的beginTime为前一个动画的结束时间,这样多个动画按照必定的顺序执行。

2.使用timeOffset属性能够在一组动画中设置相对于其余动画,延迟执行必定的时间段。

4.动画的添加与删除

咱们建立好动画对象能够调用CALayeraddAnimation:forKey:方法将动画添加到layer上并指定动画的标记key用于后续的删除操做,若是要移除一个动画能够调用CALayerremoveAnimationForKey:方法移除key值对应的动画效果、或者你能够调用removeAllAnimations方法删除layer附带的全部动画效果,而且remove方法是当即生效的,动画当即结束执行。

三.CoreAnimation动画实现方式

经过更改Layer的属性值实现动画。(属性必须是Animatable关于CALayer的可作动画的属性)

在这里更改属性值建立动画有两种:

第一种是隐式动画(Animating a change implicitly),隐式动画使用默认的时间(0.25秒)和动画属性去执行动画。当咱们更改layer的属性值时,会触发隐式动画。当修饰的layer对象在layer-tree中时,更新会当即执行。若是layer对象的显示效果没有当即改变,CoreAnimation会为这些改变建立一个触发器而且添加一个或者多个隐式动画去执行。所以,像theLayer.opacity = 0.0;这样的更改会引起CoreAnimation为你建立一个Animation对象,并把这个Animation对象加入到下一次更新循环(next update cycle.)中去执行。

第二种是显式动画(Animating a change explicitly),须要你本身为使用的动画对象配置属性。如上的隐式动画若是要显示的执行,则须要咱们建立一个Animation对象(如:CABasicAnimation)。并为这个对象配置动画参数。咱们能够在把这个Animation添加到layer以前设置Animation的开始和结束值、动画的执行时间、或者设置其余的动画属性。当建立一个Animation对象,你须要指定动画的KeyPath并设置动画参数。去执行动画时,只须要调用addAnimation:forKey方法去将你想要执行的动画添加到layer上。显示动画的layer属性更新不像隐式动画,显示动画只是建立动画不会更改layer-tree中的属性值。在动画的结束CoreAnimation会移除动画并使用它当前的属性值重绘layer。若是你想要经过显示动画永久更改layer-tree中的属性值,那么你须要在动画结束时手动设置layer的属性。

隐式动画和显示动画一般是在当前的运行环(run loop)结束以后执行的,而且当前线程必定要有一个运行环去执行Animations。若是更改多个属性或者为layer添加Animations,那么这些改变或者添加的动画是并发执行的。固然也能够为每一个动画设置特定的执行时间,具体的使用下面会有代码。

1.使用UIView的分类实现动画

尽管咱们能够直接使用CAAnimation接口实现想要的动画效果,可是对于简单的动画使用CAAnimation仍是须要额外的步骤,其实苹果已经为咱们作了一些扩展,这些扩展在UIView的分类中实现,因此对于UIView自带的layer咱们能够直接使用UIView去实现一些简单的动画。关于如何实现UIView自带的layer动画能够看这里How to Animate Layer-Backed Views.

下面是经过UIView动画分类接口实现的动画效果:

1.实现更改view透明度动画


透明度

2.实现更换view背景色动画并延迟0.5秒执行


背景色

3.实现view移动动画


移动

4.实现view旋转动画


旋转

5.实现view放大缩小动画


放大

缩小

6.实现view弹簧效果动画


弹簧

7.实现view系统删除动画


系统删除

8.实现过渡动画


过渡

9.事务实现view翻转动画


事务翻转

10.实现view组合动画


UIView组合动画


2.使用CAAnimation实现动画

UIView自带的动画是苹果给我提供的CAAnimation的封装,其动画实现相对来讲比较简单方便,咱们只须要在block内更改UIView的属性即可以实现一些简单的动画效果。可是其局限性也是十分明显的。对于一些复杂动画、高级动画UIView自带的动画就显得无能为力,这时CAAnimation的强大之处就无语言表了。其实CAAniamtion动画的使用也不是很困难,可是其对于控制动画执行时间、数学知识运用以及超常的想象力等要求就比较高了。

下面是对照UIView自带动画接口实现的一些动画,并简单列举了几个动画效果,对于UIView自带动画来讲实现相对困难,以此来展现下CAAnimation的强大。

1.实现更改view透明度动画


透明度

2.实现更改view的背景色


背景色

3.实现view移动动画


移动

3.实现view曲线移动


曲线移动

4.实现view旋转动画


旋转

5.实现viewX轴翻转动画


X轴翻转

6.实现viewY轴翻转动画


Y轴翻转

7.实现view放大缩小动画


放大

缩小

函数实现

8.实现view过渡动画


过渡

函数实现

9.实现view弹簧动画


弹簧动画

函数实现

10.事务动画


事务

11.实现view组动画


组动画

函数实现

四.自定义动画

上面说了那么多,可是建立的动画效果都仍是比较普通的。对于CAAnimation类族,这些只是他们强大功能的冰山一角。可是不管多么复杂的动画其实都是上面这些基础动画的聚合,只要我么可以想象出动画的执行逻辑,咱们就可使用CAAnimation类族实现相对复杂的动画。本人的想象力有限,因而我模仿微博的tabbar中间item点击按钮的点击弹出菜单效果,实现了简单的弹出菜单,具体的代码:clone git代码。因为不能上传视频因此这里就不放效果图了,感兴趣的能够去下载工程运行试看。

五.总结

这篇博客主要介绍了CoreAnimation的动画使用,以及动画的实现。虽然CAAnimation类族的使用并不困难,可是仍是有不少细节须要注意的。

1.显示动画在执行过程当中的属性值修改并不会影响到layer-tree中的layer属性值,因此在动画执行结束,layer会回到原始状态。

2. 对于CALayer若是屡次调用addAnimation: forKey:只会执行最后添加的Animation对象。

3. 对于一些属性值不是OC对象的须要将对应的结构体或者基本数据类型转化为OC对象,比较特殊的是颜色值,要将UIColor转化为CGColor并对其进行id强转。具体的属性值转换下表有对应的转换对象。

4. 其实动画中比较强大的属性是CALayertransform属性,该属性能够实现3D动画效果,苹果也给出了一些transform的便捷keyPath,如rotation.xscale.ytranslation.z等。

5. 还有一点须要注意的是CAAnimation对象属性的设置必须在添加到CALayer以前,不然设置不起做用。

作为一个iOS菜鸟但愿本身可以不断提升本身的撸码能力的同时,也给你们带来更多的贡献;立刻就要十一了, 提早祝你们节日快乐、happy coding。

终于结束了,谢谢你们的阅读!以为不错的朋友记得点个喜欢哦!有什么不足的但愿你们评论指出,或者QQ我(1034131730)。


注:如下是一些小的细节

属性值得转换:

当咱们建立动画更改的layer属性为C语言的结构体时,咱们必须将这些结构体转换为一个对象赋值给layer下面的表列出了C语言类型对应的转换Obj-C对象。


动画属性值转换

CATransform3D的一些便捷的KeyPaths:


CATransform3D
相关文章
相关标签/搜索