Animating between real and placeholder values

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?

Answered by nickfromsf in 732894022

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.

Here's a clip of the incorrect effect in action: https://imgur.com/a/NqJRVra

finalTemp is set to 0 when the displayed temp value turns into "..." and then you can see the wiggle as it attempts to interpolate from 0 to the new value, but it's already at the new value.

Accepted Answer

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.

Animating between real and placeholder values
 
 
Q