前言

上周末,又进行了一次实验室内部的iOS分享会。这次是小学弟给我们讲的CAMediaTiming以及Runloop的一些内容。讲的很细,也很深=。=

其中提到了一点:CALayer的时间坐标系,也就是本文要讲的主要内容

时间坐标系

时间坐标系这个名字听着有点奇怪,类似layer的空间坐标系。它的意思是:每个CALyer都有自己的时间刻度;在同一个全局时间下,每个CALyer自己的时间是可以不一样的。而CAAnimation参照的时间则是他所属的CALyer的时间系。

CAMediaTiming

CAMediaTiming是一个协议,定义了beginTimetimeOffsetspeed等属性。CALayer以及CAAnimation都实现了该协议。

CALayer中设置CAMediaTiming的相关属性是用来更改CALyer的时间系,也就是改变每一时刻的CALyer的时间。而在CAAnimation中设置这些属性,则是为了修改动画的相关时间属性;这些时间属性都是对应相应的layer的时间系的。

CALayer的时间如何计算

t = (tp - begin) * speed + offset

上面的公式就是计算当前layer的时间。

  1. tp:父layer当前的时间
  2. begin:当前layer的beginTime属性
  3. speed:当前layer的speed属性
  4. offset:当前layer的timeOffset属性

那么如何获取root layer的时间呢:

1
[[rootLayer convertTime:CACurrentMediaTime() fromLayer:nil]];

看一段代码:

1
2
NSLog(@"global time %f", CACurrentMediaTime());
NSLog(@"layer time %f", [self.fatherLayer convertTime:CACurrentMediaTime() fromLayer:nil]);

它的输出如下:

1
2
2017-07-24 11:11:44.909 test2[67727:3342255] global time 247346.964195
2017-07-24 11:11:44.910 test2[67727:3342255] layer time 247356.964486

可以看到在不改变任何layer的属性的情况下:layer的时间和全局时间是一致的;那么根据父子时间坐标系的关系,如果父子layer都是默认设置,那么他们的时间是相同的,都是全局时间

CALyer时间与动画时间

一个CAAnimation的durationstartime等属性是基于哪个时刻的CALyer时间呢?是运行完[layer addAnimation:]这一函数的那个时刻吗?

来看段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"position.x"];

/* 动画的设置 */
basec.duration = 2.0f;

[self.fatherLayer addAnimation:basic forKey:nil];

// 打印addAnimation时候的时间
NSLog(@"layer time %f", [self.fatherLayer convertTime:CACurrentMediaTime() fromLayer:nil]);

// 主线程sleep 4秒钟
[NSThread sleepForTimeInterval:4.0f];

// 打印sleep之后的时间
NSLog(@"layer time %f", [self.fatherLayer convertTime:CACurrentMediaTime() fromLayer:nil]);

来看看输出:

1
2
2017-07-24 11:11:44.910 test2[67727:3342255] layer time 247356.964486
2017-07-24 11:11:48.911 test2[67727:3342255] layer time 247360.965715

两次打印的时间确实相差4s,而且动画也是正常执行的。所以可以看到动画的参考时间点并不是addAnimation的那一刻;而应该是主线程runloop进行界面更新,动画真正开始的那一刻。

还有一些其他的…

来两张分享会的现场照片

share1

share2

参考