动画的暂停与恢复原理
之前在做一个语音播放功能的时候,封面随着播放而旋转,而封面的旋转动画会随着音频的播放状态而改变。那么怎么暂停和恢复这个旋转动画呢?对于面向搜索引擎编程的程序员来说,立马在谷歌输入“CAAnimation pause”字样立刻就找到了如下代码:
1 | func pause() { |
CMD+R
跑一下,OK,完美运行。
解决了问题之后,那么为什么这段代码能够暂停和恢复动画呢?CACurrentMediaTime()
、beginTime
、timeOffset
又是些什么东西,起什么作用呢?
我们一个一个来看。
根据文档,CACurrentMediaTime()
返回的是 CoreAnimation
的绝对时间,换一种说法就是其返回的是手机自开机以后所经过的秒数。其时间轴的参考系是手机的运行时间而不是现实世界的真实时间。
beginTime
指定了 layer 相对于其父视图的开始时间,默认为0。
文档说得比较抽象,还是要实践出真知。来看下面一段代码:
1 | let view = UIView() |
运行一下,可以看到最开始的时候,我们添加的视图是不会显示的,在等待 2 秒之后才会出现。如果把代码改一下:
1 | DispatchQueue.main.asyncAfter(deadline: .now() + 5) { |
这时发现视图是一开始就绘制出来了,之后也没有消失。
再把代码改一下:
1 | DispatchQueue.main.asyncAfter(deadline: .now() + 5) { |
此时,可以观察到,视图在一开始被绘制了出来,但是在 5 秒之后视图消失,2 秒之后视图再次出现。
beginTime 实际上是设置的一个时间点,它标记了本对象相对于父对象的启动时间。假如父对象的时间基点是100,第一个例子中就是相对于父对象 2 秒后启动,也就是102秒的时候启动。第二个例子同样是102秒的时候启动,但是此时父对象已经到了105了,时间不可能倒流,所以这样设置没有效果。第三个例子,时间来到105秒,此时设置的启动时间是当前的时间点再加上2秒,也就是107秒的时候启动,所以能能正常运行。
解释有问题
第三个例子中的 beginTime 如果是相对于父对象的话,应该是107 秒后启动,为什么也会是 2 秒后启动呢?
timeOffset
的概念理解起来就容易得多了。它的作用就是将 layer 设置成某一个时刻的固定状态。比如说一个 10 秒的进度动画,在第 2.5 秒的时候是绘制了 90 度,那么将 timeOffset
设置为 2.5,那么 layer 就会呈现出 90 度的样子。
需要注意的是,timeOffset
的时间是layer 的本地时间,写代码的过程中要先计算出本地时间再进行设置。