I'm working in Swift 5 (Xcode 13.4.1) and I've got 3 animations that should run after a button is pressed. One of the animations, 'rotate', is defined by a function. The rotate animation doesn't stop after duration ends, it just restarts. I'm trying to stop the rotation animation using self.UI_Image_Name.layer.removeAllAnimations
.
I can't get my code to wait until animations are finished to run the removeAllAnimations
line. I've been trying to follow this tutorial: Waiting until the task finishes
Here's my current code:
@IBAction func flipButtonPress(_ sender: UIButton) {
// flipResult.image = results[Int.random(in: 0...1)]
self.animationGroup.enter()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now(), execute: { () -> Void in
//Slide coin image to middle of screen
UIView.animate(withDuration: 3, delay: 0,
options: [.curveEaseIn, .curveEaseOut],
animations: {
self.coinImage.frame.origin.y = 220
})
//Rotate Coin image
UIView.animate(withDuration: 11, delay: 3,
options: [.curveEaseIn, .curveEaseOut],
animations: {
self.coinImage.rotate()
})
//Fade away coin image
UIView.animate(withDuration: 5, delay: 6,
options: [],
animations: {
self.coinImage.alpha = 0.5
})
self.animationGroup.leave()
})
self.animationGroup.enter()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now(), execute: { () -> Void in
self.coinImage.layer.removeAllAnimations()
})
self.animationGroup.leave()
}
}
extension UIImageView{
func rotate() {
let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.toValue = NSNumber(value: (Double.pi * 2) * 22)
rotation.duration = 11
rotation.isCumulative = true
rotation.repeatCount = Float.greatestFiniteMagnitude
rotation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
rotation.beginTime = CACurrentMediaTime() 3;
self.layer.add(rotation, forKey: "rotationAnimation")
}
}
CodePudding user response:
Simplist Option
Okay, so there's a lot of stuff here, for one, you can remove the animation group, as if its only purpose is to help run code when the animations are finished, then we won't need it.
Secondly, animations come with a completion
callback. So change your Fade away coin image
to this:
UIView.animate(withDuration: 5, delay: 6, options: []) {
self.coinImage.alpha = 0.5
} completion: { _ in
self.coinImage.layer.removeAllAnimations()
}
This means that after the 6 second delay and the 5 second animation, the coins layer animations will be removed
Another Option
If this doesn't create the desired effect, then instead you can try this (I personally try to avoid using this where I can as it can be prone to breaking if animation times are changed):
DispatchQueue.main.asyncAfter(deadline: .now() <#Delay in seconds#>) {
<#code#>
}
This will run the code inside the closure after the given number of seconds.