I put together a small view in SwiftUI which shows a temperature gauge and then hooked it up to a simple animation like so:
Arc(temp: finalTemp).animation(.easeIn, value: finalTemp)
This works great, it animates nicely when I set the temp from the initial value of 0 to whatever the finalTemp
value is.
When refreshing this data, I want to display a placeholder state and animate this view back to 0 and then when the data arrives, up to its new value. I attempted this by adding a @Binding var placeholder: Bool
to the view and an onChange handler for the placeholder binding:
.onChange(of: placeholder) { _ in
if placeholder == true {
finalTemp = 0
} else {
finalTemp = 80
}
}
However, I can't get the view to animate back to 0 when the placeholder binding is set on. The change handler is called correctly and the finalTemp
state is set to 0 as I expected, but the animation never occurs and the view stays reflecting the previous value. When the placeholder binding is toggled false again, the view does update and animate to the new value, in fact it wiggles like it's easing all the way from 0.
From a UIKit perspective, this strikes me as a classic case of not running an animation on the main thread. But every call that sets finalTemp
occurs on the main thread and I don't see how anything else I'm doing would push a SwiftUI animation onto a thread other than main.
What am I doing wrong that prevents the view from animating to zero in the placeholder state?
The actual issue here was completely unrelated to the way bindings update. I added a sleep
inside of a Task
to more clearly see the animation impact and that was having side effects on the animations. I would not have expected a sleep in a Task to impact animations triggered by binding changes outside of that task, but that's clearly not the case. Probably wise to not sleep anywhere that is not an async marked function if you're this close to SwiftUI.