开始/停止图像视图旋转动画

5
我有一个启动/停止按钮和一个图像视图,我想要旋转这个图像视图。当我按下按钮时,我希望开始旋转图像视图,并在再次按下按钮时停止旋转。目前我正在使用UIView动画,但我还没有找到一种停止视图动画的方法。我希望图像能够旋转,但当动画停止时,图像不应返回到起始位置,而是继续动画。
var isTapped = true

    @IBAction func startStopButtonTapped(_ sender: Any) {
       ruotate()
       isTapped = !isTapped
    }

    func ruotate() {
        if isTapped {
            UIView.animate(withDuration: 5, delay: 0, options: .repeat, animations: { () -> Void in
            self.imageWood.transform =     self.imageWood.transform.rotated(by: CGFloat(M_PI_2))
            }, completion: { finished in
            ruotate()
            })
    }  }

这是我的代码,但它的表现不像我期望的那样。


1
你可以使用 CABasicAnimation 来实现启动/停止动画。 - Ahmad F
5个回答

14

Swift 3.x

启动动画

let rotationAnimation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
    rotationAnimation.toValue = NSNumber(value: .pi * 2.0)
    rotationAnimation.duration = 0.5;
    rotationAnimation.isCumulative = true;
    rotationAnimation.repeatCount = .infinity;
    self.imageWood?.layer.add(rotationAnimation, forKey: "rotationAnimation")

停止动画

self.imageWood?.layer.removeAnimation(forKey: "rotationAnimation")

Swift 2.x

开始动画

let rotationAnimation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
    rotationAnimation.toValue = NSNumber(double: M_PI * 2.0)
    rotationAnimation.duration = 1;
    rotationAnimation.cumulative = true;
    rotationAnimation.repeatCount = .infinity;
    self.imageWood?.layer.addAnimation(rotationAnimation, forKey: "rotationAnimation")

停止动画

self.imageWood?.layer.removeAnimation(forKey: "rotationAnimation")

4
这将停止动画,但图层将立即跳到最终位置。如果你想让它停留在当前状态,需要采取额外的步骤:一种选择可能是从呈现图层中获取图层的转换,将该转换设置在实际图层上,然后移除动画。另一个选择是将动画速度设置为零。 - Duncan C
@DuncanC 谢谢您的建议,同时我邀请您用另一种方式编辑答案..!! - Salman Ghumsani
我刚刚发布了一个带有替代解决方案的答案。 - Duncan C

5
如果您使用 UIView 动画,操作系统仍会创建一个或多个 CAAnimation 对象。因此,要停止 UIView 动画,您仍然可以使用以下方法:

myView.layer.removeAllAnimations()

或者,如果您使用图层上的CAAnimation创建动画:

myLayer.removeAllAnimations()

无论哪种情况,您都可以捕获当前动画的状态,并在移除动画之前将其设置为最终状态。如果您正在对视图的变换进行动画处理(例如本问题),则该代码可能如下所示:
func stopAnimationForView(_ myView: UIView) {

  //Get the current transform from the layer's presentation layer
  //(The presentation layer has the state of the "in flight" animation)
  let transform = myView.layer.presentationLayer.transform

  //Set the layer's transform to the current state of the transform
  //from the "in-flight" animation
  myView.layer.transform = transform

  //Now remove the animation 
  //and the view's layer will keep the current rotation
  myView.layer.removeAllAnimations()
}

如果您需要动画化的属性不是 transform,则需要更改上面的代码。

这很完美,但如果我想从上次暂停的状态重新开始,它就无法工作... - Saifan Nadaf
@SaifanNadaf,请看我对这个问题的另一个答案,使用UIViewPropertyAnimator。这个答案会破坏动画,使其无法恢复。另一个答案允许您暂停和恢复动画。也可以“手动”暂停和恢复CAAnimation,但这很棘手,难以理解。UIViewPropertyAnimator更容易使用。 - Duncan C

2
使用您现有的代码,可以按如下方式实现:
    var isTapped = true

@IBAction func startStopButtonTapped(_ sender: Any) {
    ruotate()
    isTapped = !isTapped
}

func ruotate() {
    if isTapped {
        let rotationAnimation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
        rotationAnimation.toValue = NSNumber(value: Double.pi * 2.0)
        rotationAnimation.duration = 1;
        rotationAnimation.isCumulative = true;
        rotationAnimation.repeatCount = HUGE;
        self.imageWood?.layer.add(rotationAnimation, forKey: "rotationAnimation")
    }else{
        self.imageWood?.layer.removeAnimation(forKey: "rotationAnimation")
    }
}

那是一个很大的重复次数。 - Byron Coetsee

2

苹果在iOS 10中添加了一个新类UIViewPropertyAnimator。通过使用UIViewPropertyAnimator,您可以轻松创建基于UIView的动画,并且可以暂停、反向和前后拖动。

如果您重构代码以使用UIViewPropertyAnimator,则应该能够暂停和恢复动画。

我在Github上有一个示例项目,演示如何使用UIViewPropertyAnimator。建议您查看一下。


谢谢 Duncan。我希望支持 iOS 9+,所以现在可能是第二个选择。 - Edoardo
此外,我发现你的库虽然相当出色,但是适应我的项目有点复杂。我不知道在视图控制器中应该实现旋转逻辑。我知道有一个viewAnimator,但不知道如何将其应用到一起。 - Edoardo
请看我的第二个答案。那里展示了如何停止动画并使其在当前状态下冻结。 - Duncan C

1
你的代码使图片旋转了2PI角度,但如果在旋转没有结束时点击按钮,动画将在停止之前完成,这就是为什么它回到初始位置的原因。
你应该使用CABasicAnimation来使用旋转,可以随时停止并保持最后位置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接