I have a button and when pressed it runs a CABasicAnimation in 2 seconds. The first time I press the button the animation runs fine and the layer is filled red. The second time I press the button the animation doesn't run again. The red layer disappears because I remove it but it doesn't start back from the beginning again.
In the code below the basicAnimation is a class property. I also tried creating it inside the buttonPressed method itself which made no difference and then I tried adding it as an optional var basicAnimation: CABasicAnimation?
, instantiating it inside the buttonPressed method, then setting it to nil inside the animationDidStop(_:finished:)
delegate method but neither worked.
Why doesn't is run again?
let shapeLayer = CAShapeLayer()
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
// var basicAnimation: CABasicAnimation? // I tried this
override func viewDidLoad() {
super.viewDidLoad()
let circularPath = UIBezierPath(arcCenter: view.center, radius: 100, startAngle: -.pi/2, endAngle: 3 * .pi/2, clockwise: true)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 10
shapeLayer.strokeEnd = 0
view.layer.addSublayer(shapeLayer)
}
@objc func buttonTapped() {
// basicAnimation = CABasicAnimation(keyPath: "strokeEnd") // I tried this
// let basicAnimation = CABasicAnimation(keyPath: "strokeEnd") // I also tried this
removeAnimation()
basicAnimation.delegate = self
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.default)
basicAnimation.fromValue = 0
basicAnimation.toValue = 1
basicAnimation.duration = CFTimeInterval(2)
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
basicAnimation.isRemovedOnCompletion = false
shapeLayer.add(basicAnimation, forKey: "myAnimation")
}
func removeAnimation() {
shapeLayer.removeAnimation(forKey: "myAnimation")
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
print("animation done") // prints once
// basicAnimation = nil // I tried this
}
I was able to make your code work just by making a new animation each time the button is tapped:
let shapeLayer = CAShapeLayer()
var basicAnimation: CABasicAnimation!
override func viewDidLoad() {
super.viewDidLoad()
let circularPath = UIBezierPath(arcCenter: view.center, radius: 100, startAngle: -.pi/2, endAngle: 3 * .pi/2, clockwise: true)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 10
shapeLayer.strokeEnd = 0
view.layer.addSublayer(shapeLayer)
}
@IBAction func buttonTapped(_ sender: Any) {
basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
removeAnimation()
basicAnimation.delegate = self
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.default)
basicAnimation.fromValue = 0
basicAnimation.toValue = 1
basicAnimation.duration = CFTimeInterval(2)
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
basicAnimation.isRemovedOnCompletion = false
shapeLayer.add(basicAnimation, forKey: "myAnimation")
}
func removeAnimation() {
shapeLayer.removeAnimation(forKey: "myAnimation")
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
print("animation done")
}