0

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.

Nime Zoste
  • 37
  • 2
  • 4
  • Change `var data: CompatibilityData?` to something like `var compData: CompatibilityData?` you have 3 different objects with same name. – canister_exister Dec 28 '18 at 20:14

2 Answers2

2

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.

NSGangster
  • 2,397
  • 12
  • 22
0

Here is the answer: If you want the progressView to 0.0, just let it animate.

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

    UIView.animate(withDuration: 2.0) {
        self.progressView.setProgress(data.percentage! / 100, animated: true)
    }
}
}
E.Coms
  • 11,065
  • 2
  • 23
  • 35
  • Wouldn't this cause two animations to go synchronously? Or does `setProgress:animated` allow full completion before a new `UIView` animation takes place? My suggestion is that the progress is being laid out but the view is not drawn to 0. Looks like a case where perhaps calling `self.progressView.layoutIfNeeded()` should redraw the progress bar to 0 one frame before the animation starts. He doesn't necessarily want the progress bar to animate back to 0 before the next animation starts – NSGangster Dec 28 '18 at 23:21