Layer动画的停止与恢复

来源:互联网 发布:国际组织工作 知乎 编辑:程序博客网 时间:2024/06/05 19:37

CALayerCAAnimation都实现了CAMediaTiming 协议,可以通过CALayer 中实现的协议中的属性来控制动画。
停止动画:通过将speed设置为0,并将timeOffset调整到合适的值。
Apple 文档说明

/* The rate of the layer. Used to scale parent time to local time, e.g. if rate is 2, local time progresses twice as fast as parent time.  Defaults to 1. */@property float speed;/* Additional offset in active local time. i.e. to convert from parent time tp to active local time t: t = (tp - begin) * speed + offset.One use of this is to "pause" a layer by setting `speed' to zero and `offset' to a suitable value. Defaults to 0. */@property CFTimeInterval timeOffset;

而恢复动画,除了上面两个属性,还需要配合beginTime 属性来让动画在正确的时间、位置恢复

##方法一// 停止- (void)pauseLayer:(CALayer*)layer{     CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];     // 让CALayer的时间停止走动     layer.speed = 0.0;     // 让CALayer的时间停留在pausedTime这个时刻     layer.timeOffset = pausedTime;}

恢复动画:

- (void)resumeLayer:(CALayer*)layer{      CFTimeInterval pausedTime = layer.timeOffset;      // 1. 让CALayer的时间继续行走        layer.speed = 1.0;      // 2. 取消上次记录的停留时刻        layer.timeOffset = 0.0;      // 3. 取消上次设置的时间        layer.beginTime = 0.0; // 可以放在pauseLayer:方法中方便理解          // 4. 计算暂停的时间(这里也可以用CACurrentMediaTime()-pausedTime)      CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;      // 5. 设置相对于父坐标系的开始时间(往后退timeSincePause)        layer.beginTime = timeSincePause;}

以上方法中有几点较为难以理解的地方,待后续解读。
1 . CALayer 中beginTime的含义。CAAnimation 的beginTime表现为从duration 的哪个点开始动画。如果不做停止/恢复动画的动作,给CALayer设置一个动画,并设置它的beginTime 属性,结果对动画的表现并没有任何影响。

疑点1解答:beginTime须设置为与层时间相关的值,如CACurrentMediaTime() + 1, 将会延迟1s开始动画;而不能直接设置为 1s。另外beginTime可以在CAGroupAnimation中控制某个动画在组动画中的起始时间。

2 . 恢复动画时,先设置layer.beginTime = 0 随后马上又设置layer.beginTime = timeSincePause 。如果少了第一句(layer.beginTime = 0),在动画第二次恢复时,不会衔接暂停时的位置,而是取决于你暂停了多少时间,这段时间内layer 本应该动画到哪个位置,它就会从那个位置恢复动画。但对第一次恢复没有影响。
这里写图片描述

2点解答:恢复动画时,先设`layer.beginTime = 0.0` 是为了后一句代码`[layer convertTime:CACurrentMediaTime() fromLayer:nil]` 能得到正确的层上的时间,如果没有layer.beginTime = 0.0, 则convert出的时间将会是上次停止动画的时间pausedTime;layer.beginTime = 0.0 这句代码可以放在停止动画方法中去。

3 . 其中,beginTimetimeOffsetCACurrentMediaTime() 之间的关系。

方法二

// 停止动画- (void)pauseAnimation{    CFTimeInterval current = CACurrentMediaTime();    CFTimeInterval pauseTime = current - layer.beginTime;    /* 实际此处      [layer convertTime:CACurrentMediaTime() fromLayer:nil] == current - layer.beginTime == pauseTime         */    layer.speed = 0;    layer.timeOffset = pauseTime;    layer.beginTime = 0.; }- (void)resumeAnimation{    CFTimeInterval pauseTime = layer.timeOffset;    CFTimeInterval timeSincePause = CACurrentMediaTime() - pauseTime;    /*     [layer convertTime:CACurrentMediaTime() fromLayer:nil] == pauseTime         */    layer.speed = 1.0;    layer.timeOffset = 0.0;    layer.beginTime = timeSincePause;}

timeSincePause 是动画停止了多长时间,动画停止了而层上的时间CACurrentMediaTime() 仍然在往前走,因此需要将layer.beginTime 往回退,才能让动画在正确的时间位置恢复。

参考:
1. CoreAnimation – Ljson
2. 控制动画的时间

0 0
原创粉丝点击