Reputation: 475
Trying to understand CoreAnimation and completion handlers.
Why does this code happen all at once, not over a 5.0 second period?
I am trying to get it to run 6 times with the 5 second duration each time for a total of 30 seconds and get "complete" to print every 5 seconds.
func animateBox() {
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: {finished in
print("complete")
})
}
@objc func buttonTapped() {
for _ in 1...6 {
animateBox()
print("animate")
}
}
Upvotes: 1
Views: 247
Reputation: 131398
Another way you could sequence the animations is to use the delay parameter, and add a delay for each step after the first:
func animateBox(step: Int) {
let duration = 5.0
UIView.animate(withDuration: duration,
delay: duration * Double(step),
options: [],
animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: {finished in
print("complete")
})
}
@objc func buttonTapped() {
for index in 0...5 {
animateBox(step: index)
print("animating step \(index)")
}
}
(Note that I changed your loop to run from 0...5 so delay =step * duration
would start at 0.)
Upvotes: 0
Reputation: 30228
for _ in 1...6 {
is executed instantly, so animateBox
is called 6 times, right after another, in a split second.
What you want to do is call each animation block inside the completion handler (which is called when the animation completes) of the previous one. Something like this:
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: { finished in
print("complete")
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: { finished in
print("complete")
UIView.animate(withDuration: 5.0, delay: 0.0, options: [], animations: {
self.myBox.layer.borderColor = self.getRandom()
}, completion: { finished in
print("complete")
...
})
})
})
But this will result in a huge completion pyramid... instead, try using animateKeyframes
:
let totalDuration = CGFloat(30)
let relativeIndividualDuration = CGFloat(1) / CGFloat(6)
UIView.animateKeyframes(withDuration: totalDuration, delay: 0, options: .calculationModeCubic, animations: {
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: relativeIndividualDuration) {
self.myBox.layer.borderColor = self.getRandom()
}
UIView.addKeyframe(withRelativeStartTime: relativeIndividualDuration, relativeDuration: relativeIndividualDuration) {
self.myBox.layer.borderColor = self.getRandom()
}
UIView.addKeyframe(withRelativeStartTime: relativeIndividualDuration * 2, relativeDuration: relativeIndividualDuration) {
self.myBox.layer.borderColor = self.getRandom()
}
...
})
Upvotes: 1