Layer动画的停止与恢复

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值