这个效果是在上一个Demo中的补充,如图所示,在回放的过程中给予暂停/继续播放的效果:
开一篇,顺带温习CAMediaTiming
因为回放的方式采用了CABaseAnimation的方案,所以暂停/播放的效果实现也需要依赖于动画方向。当动画或者动画的宿主的speed = 0时,动画相当于暂停状态,那么我们就从这里入手即可,需要注意以下几点:
1.layer的展示层和模型层;
2.相对时间与绝对时间;
3.动画各个属性对当前layer时间线的影响,也就是t = (tp - beginT) * speed + timeOffset的理解;
1.layer的展示层与模型层:展示层可以用来获得动画状态时的数据,模型层即layer,保存的layer的基础数据。显然,如果要获得动画时的属性,我们需要调用layer.presentation()
2.绝对时间:程序运行的时候,我们能获得一个”基准“时间,这个时间不受程序内的代码影响,是一个”公平、公正“的时间线,这里使用了CACurrentMediaTime()获得绝对时间;相对时间:由于我们可以调整服从CAMediaTiming()协议的时间线,而时间线的效果又是累加的,所以就产生了相对时间,通过convertTime函数可以获得相对时间;
3.t = (tp - beginT) * speed + timeOffset用来换算得到相对时间,但这里有个比较独特的地方,speed这个属性,当timeOffset == 0 && speed == 0时,t就是0,也就是说,当你先将speed置为0再去求相对时间时是不行的,这个时候不存在相对时间。我的理解是基于speed才会产生时间线的概念。
注意以上三点之后,就没有什么特别的问题了。
那么说下CAMediaTiming()在Animation和Layer上的一些问题。
1.beginTime:这个属性在Animation和Layer上有些差别,layer默认了以绝对时间线对基准,而Animation则不是,所以你不能像下面这样:
let colorAnimation = CABasicAnimation.init(keyPath: "backgroundColor")
colorAnimation.fromValue = UIColor.yellow.cgColor
colorAnimation.toValue = UIColor.blue.cgColor
colorAnimation.duration = 5
colorAnimation.beginTime = 2
这样是无效的,正确的方式应该是:
colorAnimation.beginTime = CACurrentMediaTime() + 2
当Layer设置了beginTime,一个animation加载到它上面时,好像并没有出现延迟的效果。这是因为Animation加载到layer上时,实际是copy了一份加载上去,自动同步了相对时间,也就是说,如果animation没有设置beginTime,那么他的时间使用的就是Layer的时间线。看起来Layer的时间线”慢了“2秒,是参照了绝对时间,这个时间只是一个基准的参考时间,让我们有标准去做对比和转换,并不是一个真实的时间刻度,所以如果动画采用了layer的相对时间,无论layer的相对时间与绝对时间对比是快是慢,对于animation来说都没有影响,因为此时Animation使用的是相对时间。
什么情况下需要和绝对时间进行对比呢,那就是animation进行了beginTime的设置,也就是animation采用了基准时间进行动画控制,这个时候layer的beginTime就会影响到Animation的时间控制,而且这个效果还是叠加的。
- timeOffset是个神奇的属性,时间偏移,让我们的动画可以以某个点作为分隔,以此点作为起点进行动画:
例如 A B C D E ,以D点作为分隔,则动画效果为D E A B C。
这个效果单独来说没有什么太大的使用场景,但结合speed一起的话,能巧妙地作出很多复杂的手动动画效果:
当speed = 0时,动画静止,我们可以调整timeOffset来获得某个时间点的动画效果,通过变换timeOffset,可以达到手动动画的场景。