Home > Net >  SwiftUI animation problem with a binding to a StateObject inside a NavigationView
SwiftUI animation problem with a binding to a StateObject inside a NavigationView

Time:02-24

I have an interesting situation in regards to animations in SwiftUI. In its simplified form, I have a view that shows a rectangle which, when tapped, should toggle a Bool binding and represent the change with an animated transition of color. But it seems like the animation doesn't happen when the view is inside a NavigationView and the binding is coming from a StateObject instead of simple local state. I can't explain why that would be the case, and would appreciate any thoughts.

Below is the code that shows a simplified case that reproduces the issue. The app code isn't particularly interesting; it's the default code that creates a WindowGroup and shows an instance of ContentView in it.

import SwiftUI

class AppState: ObservableObject {
    @Published var isRed = false
}

struct RectView: View {
    @Binding var isRed: Bool

    var body: some View {
        Rectangle()
            .fill(isRed ? Color.red : Color.gray)
            .frame(width: 75, height: 75, alignment: .center)
            .onTapGesture {
                withAnimation(.easeInOut(duration: 1)) {
                    isRed.toggle()
                }
            }
    }
}

struct ContentView: View {
    @StateObject var appState = AppState()
    @State private var childViewIsRed = false

    var body: some View {
        VStack {
            NavigationView {
                List {
                    NavigationLink("Link with binding to state object", destination: RectView(isRed: $appState.isRed))
                    NavigationLink("Link with binding to state variable", destination: RectView(isRed: $childViewIsRed))
                }
            }
            .frame(height: 300)

            RectView(isRed: $appState.isRed)
            RectView(isRed: $childViewIsRed)
        }
    }
}

The gif/video below is me demonstrating four things, tapping on these views from bottom to top:

  • First I tap on the very bottom rectangle - the one with a binding to a @State property. It toggles with animation as expected. I tap again to leave it gray.
  • Then I tap the second rectangle from the bottom - one with a binding to a @Published property in the @StateObject. All is well.
  • Next, I tap on the NavigationLink that leads to a rectangle that is bound to the local @State property. When I tap on the rectangle the transition is animated fine. The very bottom rectangle also animates, which makes sense since they are bound to the same property.
  • Finally I tap on the top NavigationLink, which leads to a rectangle bound to the @Published property in the @StateObject. When I tap on this rectangle though, there is no animation. The rectangle snaps to red. The rectangle below it (which is bound to the same property) animates fine, proving that the property is indeed toggled. But there is no animation inside the NavigationView. Why? What am I missing?

I've searched for existing questions. I'm aware that there are some around NavigationView (enter image description here

CodePudding user response:

To be honest with you, I am not sure why, but utilizing the animation modifier on the RectView allows the animation to occur without any issues.

struct RectView: View {
@Binding var isRed: Bool

    var body: some View {
        Rectangle()
            .fill(isRed ? Color.red : Color.gray)
            .frame(width: 75, height: 75, alignment: .center)
            .animation(.easeOut(duration: 1), value: isRed)
            .onTapGesture { isRed.toggle() }
    }
}

screen recording example

  • Related