Swift Progress View animation makes the bar go further than 100%

When using animations for the ProgressView, it works completely fine if I let the animation run out but if I try to run this code again while the animation is still going, it will add 100% to the current bar and make it go through the bar. Images should explain the situation in a more logical sense.

Progress starts at 1.0 (100%):

enter image description here

Progress is half-way through:

Progress is half-way through

The code was ran again, resulting in the progress going above 100%, although it uses the correct amount of time to finish.

The code was ran again, resulting in the progress going above 100%, although it uses the correct amount of time to finish.

Here's the code used:

self.progressView.setProgress(1.0, animated: false)
        
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  UIView.animate(withDuration: 10, delay: 0, options: [.beginFromCurrentState, .allowUserInteraction], animations: { [unowned self] in
    self.progressView.setProgress(0, animated: true)
  })
}

Thanks in advance!

Upvotes: 4

Views: 13385

Answers (2)

DonMag
DonMag

Reputation: 77690

Some quick research...

Turns out UIProgressView needs a little special effort to stop the current animation. See if this does the job for you:

    // stop any current animation
    self.progressView.layer.sublayers?.forEach { $0.removeAllAnimations() }

    // reset progressView to 100%
    self.progressView.setProgress(1.0, animated: false)

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        // set progressView to 0%, with animated set to false
        self.progressView.setProgress(0.0, animated: false)
        // 10-second animation changing from 100% to 0%
        UIView.animate(withDuration: 10, delay: 0, options: [], animations: { [unowned self] in
            self.progressView.layoutIfNeeded()
        })
    }

Upvotes: 14

deadbeef
deadbeef

Reputation: 5563

The setProgress(_:animated:) method already handles the animation for you. When the animated parameter is set to true, the progress change will be animated.

Try without the animation block :

self.progressView.setProgress(1.0, animated: false)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    self.progressView.setProgress(0.0, animated: true)
}

Also make sure this is not an autolayout issue. Check your constraints on the progress view and make sure its width is properly constrained.

Upvotes: 10

Related Questions