核心animation – 修改animation属性

我有animation

func startRotate360() { let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") rotation.fromValue = 0 rotation.toValue = Double.pi * 2 rotation.duration = 1 rotation.isCumulative = true rotation.repeatCount = Float.greatestFiniteMagnitude self.layer.add(rotation, forKey: "rotationAnimation") } 

我想要的是通过设置其重复次数为1来停止animation的能力,所以它完成当前的旋转(简单地移除animation是不好的,因为它看起来不好)

我尝试跟随

 func stopRotate360() { self.layer.animation(forKey: "rotationAnimation")?.repeatCount = 1 } 

但是我碰到了,并在控制台

试图修改只读animation

如何访问可写属性?

给一下去。 您实际上可以更改正在进行的CAAnimations。 有很多方法。 这是最快/最简单的。 您甚至可以完全停止animation并在用户不知情的情况下恢复。

您可以看到停止的开始animationfunction。 停止从表示层抓取当前旋转,并创build要旋转的animation,直到完成为止。 根据运行的animation,我还基于当前旋转z到完全旋转,将持续时间平滑为完成所需时间的百分比。 然后我用重复计数删除animation并添加新的animation。 您可以看到视图顺利旋转到最终位置并停止。 你会明白的。 放入并运行它,看看你的想法。 点击button开始,再次点击它看到它完成旋转和停止。

 import UIKit class ViewController: UIViewController { var animationView = UIView() var button = UIButton() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. animationView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) animationView.backgroundColor = .green animationView.center = view.center self.view.addSubview(animationView) let label = UILabel(frame: animationView.bounds) label.text = "I Spin" animationView.addSubview(label) button = UIButton(frame: CGRect(x: 20, y: animationView.frame.maxY + 60, width: view.bounds.width - 40, height: 40)) button.setTitle("Animate", for: .normal) button.setTitleColor(.blue, for: .normal) button.addTarget(self, action: #selector(ViewController.pressed), for: .touchUpInside) self.view.addSubview(button) } func pressed(){ if let title = button.titleLabel?.text{ let trans = CATransition() trans.type = "rippleEffect" trans.duration = 0.6 button.layer.add(trans, forKey: nil) switch title { case "Animate": //perform animation button.setTitle("Stop And Finish", for: .normal) rotateAnimationRepeat() break default: //stop and finish button.setTitle("Animate", for: .normal) stopAnimationAndFinish() break } } } func rotateAnimationRepeat(){ //just to be sure because of how i did the project animationView.layer.removeAllAnimations() let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") rotation.fromValue = 0 rotation.toValue = Double.pi * 2 rotation.duration = 0.5 rotation.repeatCount = Float.greatestFiniteMagnitude //not doing cumlative animationView.layer.add(rotation, forKey: "rotationAnimation") } func stopAnimationAndFinish(){ if let presentation = animationView.layer.presentation(){ if let currentRotation = presentation.value(forKeyPath: "transform.rotation.z") as? CGFloat{ var duration = 0.5 //smooth out duration for change duration = Double((CGFloat(Double.pi * 2) - currentRotation))/(Double.pi * 2) animationView.layer.removeAllAnimations() let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") rotation.fromValue = currentRotation rotation.toValue = Double.pi * 2 rotation.duration = duration * 0.5 animationView.layer.add(rotation, forKey: "rotationAnimation") } } } } 

结果: 结果

也许这不是最好的解决scheme,但它的工作原理,因为你说你不能修改一旦创build的CABasicAnimation属性,我们还需要删除rotation.repeatCount = Float.greatestFiniteMagnitude, if not CAAnimationDelegate method animationDidStop`永远不会被调用,采用这种方法,animation可以在没有任何问题的情况下停下来

第1步:首先声明一个variables标志来标记,因为您需要在自定义类中停止animation

 var needStop : Bool = false 

第2步:在结束后添加一个stopAnimation方法

 func stopAnimation() { self.needStop = true } 

第3步:添加一个方法来获取您的自定义animation

 func getRotate360Animation() ->CAAnimation{ let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") rotation.fromValue = 0 rotation.toValue = Double.pi * 2 rotation.duration = 1 rotation.isCumulative = true rotation.isRemovedOnCompletion = false return rotation } 

第4步:修改你的startRotate360函数来使用你的getRotate360Animation()方法

 func startRotate360() { let rotationAnimation = self.getRotate360Animation() rotationAnimation.delegate = self self.layer.add(rotationAnimation, forKey: "rotationAnimation") } 

第五步:在你的课堂上实现CAAnimationDelegate

 extension YOURCLASS : CAAnimationDelegate { func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { if(anim == self.layer?.animation(forKey: "rotationAnimation")) { self.layer?.removeAnimation(forKey: "rotationAnimation") if(!self.needStop){ let animation = self.getRotate360Animation() animation.delegate = self self.layer?.add(animation, forKey: "rotationAnimation") } } } } 

这工作,并经过testing

希望这可以帮助你