Reputation: 153
I currently have the problem that the completion of the animation function ends before the animation itself does.
The array progressBar[]
includes multiple UIProgressViews
. When one is finished animating I want the next one to start animating and so on. But right now they all start at once.
How can I fix this?
@objc func updateProgress() {
if self.index < self.images.count {
progressBar[index].setProgress(0.01, animated: false)
group.enter()
DispatchQueue.main.async {
UIView.animate(withDuration: 5, delay: 0.0, options: .curveLinear, animations: {
self.progressBar[self.index].setProgress(1.0, animated: true)
}, completion: { (finished: Bool) in
if finished == true {
self.group.leave()
}
})
}
group.notify(queue: .main) {
self.index += 1
self.updateProgress()
}
}
}
Upvotes: 2
Views: 679
Reputation: 299605
The problem is that UIView.animate()
can only be used on animatable properties, and progress
is not an animatable property. "Animatable" here means "externally animatable by Core Animation." UIProgressView
does its own internal animations, and that conflicts with external animations. This is UIProgressView
being a bit over-smart, but we can work around it.
UIProgressView
does use Core Animation, and so will fire CATransaction
completion blocks. It does not, however, honor the duration of the current CATransaction
, which I find confusing since it does honor the duration of the current UIView animation. I'm not actually certain how both of these are true (I would think that the UIView animation duration would be implemented on the transaction), but it seems to be the case.
Given that, the way to do what you're trying looks like this:
func updateProgress() {
if self.index < self.images.count {
progressBar[index].setProgress(0.01, animated: false)
CATransaction.begin()
CATransaction.setCompletionBlock {
self.index += 1
self.updateProgress()
}
UIView.animate(withDuration: 5, delay: 0, options: .curveLinear,
animations: {
self.progressBar[self.index].setProgress(1.0, animated: true)
})
CATransaction.commit()
}
}
I'm creating a nested transaction here (with begin/commit) just in case there is some other completion block created during this transaction. That's pretty unlikely, and the code "works" without calling begin/commit, but this way is a little safer than messing with the default transaction.
Upvotes: 4