iOS动画-认识CoreAnimation

447 查看

前言

在iOS中,普通的动画可以使用UIKit提供的方法来实现动画,但如果想要实现复杂的动画效果,使用CoreAnimation框架提供的动画效果是最好的选择。那么两种动画方案相比之下,后者存在的主要好处包括不仅下面这些:

  • 轻量级的数据结构,可以同时让上百个图层产生动画效果
  • 拥有独立的线程用于执行我们的动画接口
  • 完成动画配置后,核心动画会代替我们完全控制完成对应的动画帧
  • 提高应用性能。只有在发生改变的时候才重绘内容,消除了动画的帧速率上的运行代码

CoreAnimation框架下,最主要的两个部分是图层CALayer以及动画CAAnimation类。前者管理着一个可以被用来实现动画的位图上下文;后者是一个抽象的动画基类,它提供了对CAMediaTimingCAAction协议的支持,方便子类实例直接作用于CALayer本身来实现动画效果。接下来笔者会分段分别讲述上面提到的类,参考信息来自于苹果官方文档以及objc中国

CALayer

CALayer类结构

如果你喜欢动画效果,在网上开源的动画实现中总是能看到CALayer及其子类的应用,那么了解这个图层类别先从它的结构看起(此处列出了了部分属性并且去除了注释):

根据CALayer Class Reference中的描述,在每一个UIView的背后都有一个CALayer对象用来协助它显示内容,它自身管理着我们提供给视图显示的位图上下文以及保存这些位图上下文的几何信息。通过上面的代码可以看出:

  • CALayerNSObject的子类而非UIResponder的子类,因此图层本身无法响应用户操作事件却拥有着事件响应链相似的判断方法,所以CALayer需要包装成一个UIView容器来完成这一功能。
  • 每一个UIView自身存在一个CALayer来显示内容。在后者的属性中我们可以看到存在着多个和UIView界面属性对应的变量,因此我们在修改UIView的界面属性的时候其实是修改了这个UIView对应的layer的属性。
  • CALayer拥有和UIView一样的树状层级关系,也有类似UIView添加子视图的addSublayer这些类似的方法。CALayer可以独立于UIView之外显示在屏幕上,但我们需要重写事件方法来完成对它的响应操作

对于苹果为什么要把UIViewCALayer区分开来,网上已经有了一篇很详(qi)细(pa)的文章讲解这个问题都有了CALayer,为什么还要UIView

图层树和隐式动画

在每一个CALayer中,都有三个重要的层次树,它们负责相互协调完成图层的渲染展示效果。这三个层次树分别是:

  • 模型树。通过layer.modelLayer获取,当我们修改CALayer的可动画属性时,模型树对应的属性就会立刻被修改成对应的数值
  • 呈现树。通过layer. presentationLayer获取,呈现树保存着当前图层状态的显示数据,即会随着动画的过程不断更新图层的状态数据
  • 渲染树,iOS并没有提供任何API来获取这一个层次树。顾名思义,它通过结合 modelLayerpresentationLayer中设置的效果来将内容渲染到屏幕上

CALayer中的显示数据几乎都是可动画属性,这个特性为我们制作核心动画提供了很大的实践基础。在一个单独的CALayer中(也就是说这个layer并没有和任何UIView绑定),我们修改它的显示属性的时候,都会触发一个从旧值新值之间的简单动画效果,这种动画我们称之为隐式动画:

可以看到上面的代码中我单独创建了一个CALayer并且将它添加到当前的控制器视图的图层上,strokeEnd这一属性表示填充百分比。当这个属性发生变化的时候,产生了一个画圈的动画效果: