我们来测试一个层的两个属性:beginTime 和 timeOffset。
先决条件
我们使用[layer convertTime:CACurrentMediaTime() fromLayer:nil]获取CALayer的时间空间
1、给layer的beginTime赋值5.0(beginTime之前是0):
NSLog(@"CACurrentMediaTime:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
t1.layer.beginTime = 5.0 ;
NSLog(@"CACurrentMediaTime:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
结果日志是:
2014-01-15 11:00:33.811 newUserInterface[1404:70b] CACurrentMediaTime:7206.884498
2014-01-15 11:00:33.811 newUserInterface[1404:70b] CACurrentMediaTime:7201.885088
结果显示,如果我在beginTime 上加上5.0,图层的时间将减去5.0。如果动画正在播放,在beginTime 上添加 5.0 将导致动画重做 5.0 秒前的动画。
2、给layer的timeOffset赋值5.0(timeOffset之前是0):
NSLog(@"CACurrentMediaTime:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
t1.layer.timeOffset = 5.0 ;
NSLog(@"CACurrentMediaTime:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
结果是:
2014-01-15 11:09:07.757 newUserInterface[1449:70b] CACurrentMediaTime:7720.851464
2014-01-15 11:09:07.758 newUserInterface[1449:70b] CACurrentMediaTime:7725.852011
结果显示如果我在timeOffset上加5.0,图层的时间会加5.0。如果动画在飞行中,在 timeOffset 上添加 5.0 将导致动画跳转到 5.0 秒后的动画。
理解图层上的暂停和恢复动画
这里是一个例子,t1 是 UIViewController 根视图的子视图。我在 t1 上做了一个动画,它为t1.layer 的位置设置了动画。
如果给图层添加了动画,图层会根据动画的beginTime计算动画的时间,如果beginTime为0,则立即进行动画。
CABasicAnimation * b1 = [CABasicAnimation animationWithKeyPath:@"position"] ;
b1.toValue = [NSValue valueWithCGPoint:CGPointMake(160.0, 320.0)] ;
b1.duration = 10.0f ;
[t1.layer addAnimation:b1 forKey:@"pos"] ;
NSLog(@"CACurrentMediaTime:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
日志显示2014-01-15 11:25:53.975 newUserInterface[1530:70b] CACurrentMediaTime:8727.108740,表示动画将在 t1.layer 的时间空间中从 8727 开始并在 8727+10 停止。
当动画在飞行时,我使用- (void)pauseLayer:(CALayer*)layer 方法暂停动画。
layer.speed = 0.0; 会导致图层停止,图层的时间会被设置为 0。(我知道因为当设置 layer.speed 为 0 时,我会立即获取图层的时间并记录它)
layer.timeOffset = pausedTime; 会在 layer 的时间上加上 pauseTime(假设 layer.timeOffset 为 0),现在 layer 的时间是 pausedTime。
- (void)pauseLayer:(CALayer *)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; // pauseTime is the time with respect to layer's time space
layer.speed = 0.0; // layer's local time is 0
layer.timeOffset = pausedTime; // layer's local time is pausedTime, so animation stop here
}
然后我将使用- (void)resumeLayer:(CALayer*)layer 方法恢复动画。
-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
如果我在 8727+1 处停止动画(表示动画动画为 1 秒),在 pauseLayer 方法中,layer.speed = 0 会将图层的时间设置为 0,layer.timeOffset = pausedTime; 将在图层的时间上添加 pausedTime,所以图层的时间是 pausedTime。
等一下,我们现在来做个总结。 layer.speed 为 0.0,'layer.timeOffset' 等于 pausedTime,即 8727+1,图层的时间也是 pausedTime。请记住,我们很快就会使用它们。
让我们继续,我用resumeLayer方法在8727+11处恢复动画,layer.speed = 1.0;会在层的时间上加上8727+11,所以层的时间是8727+1+8727+11,layer.timeOffset = 0.0;导致layer 的时间减去 8727+1 因为 layer.timeOffset 之前是 8727+1,现在 layer 的本地时间是 8727+11。 timeSincePause 是 (8727+11-8727-1)=10。
layer.beginTime = timeSincePause; 导致图层时间减 10。现在图层的本地时间是 8727+1,这是我暂停动画的时间。
我会给你看代码和日志:
- (void)pauseLayer:(CALayer *)layer
{
NSLog(@"%f", CACurrentMediaTime()) ;
NSLog(@"pauseLayer begin:%f", [t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] ;
layer.speed = 0.0 ;
NSLog(@"pauseLayer after set speed to 0:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
layer.timeOffset = pausedTime ;
NSLog(@"pauseLayer after set timeOffset:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
}
- (void)resumeLayer:(CALayer *)layer
{
NSLog(@"%f", CACurrentMediaTime()) ;
NSLog(@"resumeLayer begin:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
CFTimeInterval pausedTime = layer.timeOffset ;
layer.speed = 1.0 ;
NSLog(@"resumeLayer after set speed to 1:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
layer.timeOffset = 0.0;
NSLog(@"resumeLayer after set timeOffset to 0:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
layer.beginTime = 0.0 ;
NSLog(@"resumeLayer after set beginTime to 0:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime ;
layer.beginTime = timeSincePause ;
NSLog(@"resumeLayer after set beginTime to timeSincePause:%f",[t1.layer convertTime:CACurrentMediaTime() fromLayer:nil]) ;
}
日志:
2014-01-15 13:14:34.157 newUserInterface[1762:70b] 15247.550325
2014-01-15 13:14:34.158 newUserInterface[1762:70b] pauseLayer begin:15247.550826
2014-01-15 13:14:34.158 newUserInterface[1762:70b] pauseLayer after set speed to 0:0.000000
2014-01-15 13:14:34.159 newUserInterface[1762:70b] pauseLayer after set timeOffset:15247.551284
2014-01-15 13:14:40.557 newUserInterface[1762:70b] 15253.950505
2014-01-15 13:14:40.558 newUserInterface[1762:70b] resumeLayer begin:15247.551284
2014-01-15 13:14:40.558 newUserInterface[1762:70b] resumeLayer after set speed to 1:30501.502810
2014-01-15 13:14:40.559 newUserInterface[1762:70b] resumeLayer after set timeOffset to 0:15253.952031
2014-01-15 13:14:40.559 newUserInterface[1762:70b] resumeLayer after set beginTime to 0:15253.952523
2014-01-15 13:14:40.560 newUserInterface[1762:70b] resumeLayer after set beginTime to timeSincePause:15247.551294
另一个问题在resumeLayer方法:为什么不将两个赋值行合并为一个layer.beginTime = timeSincePause;,原因在[layer convertTime:CACurrentMediaTime() fromLayer:nil],结果值与layer.beginTime有关。
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
说实话,我还是不知道动画背后是怎么做的,我在做的是分析结果,不是很好的解决方案。我很高兴任何对此有想法的人都可以分享。谢谢!