NO ANIMATIONS in NavigationStack or NavigationSplitView

I'm building a macOS app using SwiftUI and I recently updated to xcode 14.3. Since then I've been debugging why none of my animations were working, it turned out that the NavigationSplitView or NavigationStack are somehow interfering with all the animations from withAnimation to .transition() and everything in between.

Is anyone else experiencing this, knows a work around or knows why this is happening?

Answered by Frameworks Engineer in 750587022

We are aware of this. This is an internal bug. My sincere apologies for this particular one.

Can you let me know if this workaround works for you? Pass an animated path binding to your NavigationStack's path parameter. If you aren't using the path parameter, you should be able to simply pass a NavigationPath value to the stack's initializer and all will behave the same.

struct ContentView: View {
    @State private var path = NavigationPath()
    @State private var isOn = false

    var body: some View {
        NavigationStack(path: $path.animation(.linear(duration: 0))) {
            VStack {
                Toggle("Animate Square?", isOn: $isOn.animation(.linear(duration: 3)))
            Color.red
                .frame(width: 100, height: 100, alignment: .bottom)
                .scaleEffect(isOn ? 1.0 : 0.5)
                NavigationLink("Faux non-animated push", value: 3)
            }
            .navigationDestination(for: Int.self) { _ in
                Color.orange
            }
            .toolbar { Spacer() }
        }
    }
}

In the code below, notice how I pass a duration of 0 to the $path.animation(.linear(0)). This achieves a non-nil animation, but doesn't force adoption of animated pushes if you don't want them. The workaround is providing that animation to the path. The bug erroneously disabled all animations when a stack animation wasn't provided. (Rest assured we now have tests for this, and sorry again for the inconvenience)

Accepted Answer

We are aware of this. This is an internal bug. My sincere apologies for this particular one.

Can you let me know if this workaround works for you? Pass an animated path binding to your NavigationStack's path parameter. If you aren't using the path parameter, you should be able to simply pass a NavigationPath value to the stack's initializer and all will behave the same.

struct ContentView: View {
    @State private var path = NavigationPath()
    @State private var isOn = false

    var body: some View {
        NavigationStack(path: $path.animation(.linear(duration: 0))) {
            VStack {
                Toggle("Animate Square?", isOn: $isOn.animation(.linear(duration: 3)))
            Color.red
                .frame(width: 100, height: 100, alignment: .bottom)
                .scaleEffect(isOn ? 1.0 : 0.5)
                NavigationLink("Faux non-animated push", value: 3)
            }
            .navigationDestination(for: Int.self) { _ in
                Color.orange
            }
            .toolbar { Spacer() }
        }
    }
}

In the code below, notice how I pass a duration of 0 to the $path.animation(.linear(0)). This achieves a non-nil animation, but doesn't force adoption of animated pushes if you don't want them. The workaround is providing that animation to the path. The bug erroneously disabled all animations when a stack animation wasn't provided. (Rest assured we now have tests for this, and sorry again for the inconvenience)

If you are using NavigationSplitView without stacks, unfortunately, you'll need to use the same workaround above. Which effectively means shimming a NavigationStack as the root of the column in which you want the animations, and then structuring your NavigationLinks such that they aren't targeting the stack.

What is ETA on the fix for this, this workaround doesn't work 100% of the time for me.

I am having the same problem with NavigationSplitView, I don't quite understand your fix proposal. When do you see this fix getting released, if it's not long I'd rather move on.

Same issue on iOS16 with NavigationStack nested in a Paging style tab view

I am running iOS17 with Xcode 15.0.1 and just ran into this bug I believe. I followed your work around and the animation returned. Was this supposed to be fixed with iOS17 and 15.0.1?

I copy and pasted the ContentView listen above on mac OS sonoma (14) (XCode 15) and the issue is still there, no animations even by using the animated path.

I NEVER want to see these unwanted animations of the title bar text flying off the screen. Why isn't there an NSDefault option to make sure that the item's unwanted and unasked for extraneous distracting new animations are disabled? And disabled through a standard mechanism such as Defaults.

I want to make sure that the animation in the nav bar is disabled and always so. Seeing items randomly flying off of the screen is a visual distraction that adds unhelpful noise to the UI. It distracts the user. It doesn't help them accomplish their task. This push in the UI team to animate EVERYTHING - whether it serves a useful purpose or not - is taking Apple far away from setting the standard in user interface experiences that HELP the user. There is NO useful purpose that helps the user accomplish their task by having a STATIC user interface element fly off the screen (or fly on the screen for that matter).

It's a distraction - not a helpful aid.

Unwanted and unexpected motion is a VISUAL DISTRACTION to users. ESPECIALLY among UI elements that are static… until they suddenly start flying across the screen.

It serves no purpose at all to help the user accomplish their task and sudden motion actively pulls the user's attention AWAY from what they are trying to focus on. Sudden unexpected motion is bad, startling, distracting and should be actively avoided in productive user interfaces.

For the love of useful interfaces, let us developers - THROUGH A STANDARD MECHANISM - turn OFF this insipid "flying static UI text". No one wants it. No asked for it. It serves no constructive purpose to the user at all.

Now, as developers, how the hell do we turn this unwanted animation OFF in the Navigation title bar?

Thanks for the workaround... shame this issue is still around in iOS 18 Beta 2 / Xcode 16 beta 2.

For anyone else, my code has to look like this :

@State private var path = NavigationPath()

// body {
//   Navigation Split View Detail ... {
        NavigationStack(path: $path.animation(.linear(duration: 0))) {
            VStack {
                Text(document.imageUrl?.absoluteString ?? "")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .id(document.imageUrl)
                    .transition(.slide)
                    .overlay(
                        alignment: .bottomTrailing,
                        content: makePrevNextView
                    )
            }
        }
//   }
// }

Note, the VStack is necessary and fails without it...

NO ANIMATIONS in NavigationStack or NavigationSplitView
 
 
Q