【问题标题】:Is there a way to pause a CABasicAnimation?有没有办法暂停 CABasicAnimation?
【发布时间】:2010-02-21 18:20:04
【问题描述】:

我有一个基本的 iPhone 旋转动画。有什么方法可以“暂停”动画以保持视图的位置?我想这样做的一种方法是使动画“完成”而不是对其调用“删除”,我该怎么做?

CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2];
rotationAnimation.duration = 100;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = HUGE_VALF;
rotationAnimation.removedOnCompletion = NO;
rotationAnimation.fillMode = kCAFillModeForwards;
[myView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];

【问题讨论】:

    标签: iphone core-animation cabasicanimation


    【解决方案1】:

    最近出现的苹果技术说明QA1673描述了如何暂停/恢复图层的动画。

    暂停和恢复动画列表如下:

    -(void)pauseLayer:(CALayer*)layer
    {
        CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
        layer.speed = 0.0;
        layer.timeOffset = pausedTime;
    }
    
    -(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;
    }
    

    编辑: iOS 10 引入了新的 API - UIViewPropertyAnimator,它允许以更交互的方式处理动画,例如,它可以轻松暂停和恢复动画或“寻找”它到某个特定的进度值。

    【讨论】:

    • 这对我来说很好,但是,当我处于暂停状态并旋转我的设备时,我失去了与应用程序交互的所有能力。它实际上并没有崩溃,但它似乎“冻结”了。是否与“willAnimateRotationToInterfaceOrientation”有冲突?
    • @YoCoh,它确实可以暂停视图的标准旋转动画,并且在动画期间可能会禁用用户交互(可能就是这种情况)并且标准动画无法完成,最终导致 UI 卡住处于禁用状态。不知道如何解决它
    • @Vladimir 如何以相反的方向恢复动画?我知道在这种情况下速度一定是负数,但是timeOffsetbeginTime 呢?
    • 这只有在“简历”代码中的layer.speed = 1.0 时才能可靠地工作。将其设置为任何其他值(例如匹配原始动画速度)会导致“恢复”不自然地跳转。
    【解决方案2】:

    Swift 3 的答案:

    致谢@Vladimir

    代码:

     func pauseAnimation(){
      let pausedTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
      layer.speed = 0.0
      layer.timeOffset = pausedTime
    }
    
    func resumeAnimation(){
      let pausedTime = layer.timeOffset
      layer.speed = 1.0
      layer.timeOffset = 0.0
      layer.beginTime = 0.0
      let timeSincePause = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
      layer.beginTime = timeSincePause
    }
    

    【讨论】:

      【解决方案3】:

      设置视图层的当前状态以匹配presentationLayer 的状态,然后移除动画:

      CALayer *pLayer = [myView.layer presentationLayer];
      myView.layer.transform = pLayer.transform;
      [myView.layer removeAnimationForKey:@"rotationAnimation"];
      

      【讨论】:

      • 虽然这会保存位置,但当我将动画重新添加到视图时,它并不能作为起点,视图移动得稍微慢一些,以适应相同数量的较短距离时间。是否需要采取其他步骤才能从中断处恢复动画?
      【解决方案4】:

      感谢@Vladimir 和@Supratik-Majumdar

      Swift 5.1 作为 CALayer 扩展

          extension CALayer
          {
              func pauseAnimation() {
                  if isPaused() == false {
                      let pausedTime = convertTime(CACurrentMediaTime(), from: nil)
                      speed = 0.0
                      timeOffset = pausedTime
                  }
              }
      
              func resumeAnimation() {
                  if isPaused() {
                      let pausedTime = timeOffset
                      speed = 1.0
                      timeOffset = 0.0
                      beginTime = 0.0
                      let timeSincePause = convertTime(CACurrentMediaTime(), from: nil) - pausedTime
                      beginTime = timeSincePause
                  }
              }
      
              func isPaused() -> Bool {
                  return speed == 0
              }
          }
      

      【讨论】:

      • 我怎样才能改变动画速度值,它只有在值为 1.0 时才有效。有什么想法吗?
      • 我从未尝试将动画速度更改为 0 或 1 以外的值。
      【解决方案5】:

      您可以使用计时器或处理动画委托方法:

      - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
      

      这是我的代码:

      // ...
      [self startAnimation];
      // ...
      
      - (void)startAnimation {
      CABasicAnimation* rotationAnimation;
      rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
      rotationAnimation.fromValue = [NSNumber numberWithFloat:0];
      rotationAnimation.toValue = [NSNumber numberWithFloat: M_2_PI];
      rotationAnimation.duration = 1.0;
      rotationAnimation.cumulative = YES;
      // rotationAnimation.repeatCount = 0; // <- if repeatCount set to infinite, we'll not receive the animationDidStop notification when the animation is repeating
      rotationAnimation.removedOnCompletion = NO;
      rotationAnimation.fillMode = kCAFillModeForwards;
      rotationAnimation.delegate = self; // <- hanlde the animationDidStop method
      [myView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
      
      }
      
      - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
      if (shouldContinueAnimation) // <- set a flag to start/stop the animation
          [self startAnimation];
      }
      

      希望对你有帮助。

      【讨论】:

      • 注意!!!除非您有特殊需要这样做,否则这不是推荐的方式。想象一下,你有一个无限运行的动画。当我们在应用程序进入后台之前暂停动画然后在进入前台时尝试恢复动画时,此方法将无济于事。
      【解决方案6】:

      最简单的一个

      self.viewBall.layer.position = self.viewBall.layer.presentationLayer().position
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-09
        • 2020-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多