Search code examples
iosswiftuikituiprogressview

UIProgressView animation works correctly only once


I doing some HTTP request, setting a class property when the HTTP response is received and updating a progress bar value with willSet. The progress bar animation works only once.

var data: CompatibilityData? {
    didSet {
        self.progressView.setProgress(0.0, animated: false)

        UIView.animate(withDuration: 2.0) {
            self.progressView.setProgress(data.percentage! / 100, animated: true)
        }
    }
}

...

let task = URLSession.shared.dataTask(with: url) { data, response, error in
    ...

    if let data = data {
        ...

        DispatchQueue.main.async {
            if let r = response {
                self.data = r
            }
        }
     }
}

task.resume()

When I'll receive HTTP response a second time, the expected behavior reset progress to 0 and animate it from 0 to data.percentage again. Currently it moves from old data.percentage to new data.percentage.


Solution

  • It helps to understand how animations work at an abstract layer. Just because the progress VALUE has changed doesn't mean the stroke path of the bar that represents it's value has updated to reflect it's change to 0.

    What this means is when the view is looking to animate it's gonna go from it's "old stroke path" value, still at the previous value, to the "new stroke path" value, the updated value.

    In order for everytime the percentage changes you want to show the animation from 0, you must update the view's layout and not just the underlying value.

    Calling

    self.progressView.layoutIfNeeded()

    After setting the underlying progress value will update the progressView Bar to reflect the proper value on the next drawing cycle and will occur before the animation starts so that the animation will go from 0 to the new value.

    Unless you want to take @E.Coms approach and wait for the view to finish animating back down to 0 before animating to the new value. Albeit this looks pretty cool, it might not be the desired effect you have.