How to replace tabBar with bottomBar with smooth animation in SwiftUI?

I am trying to replace the navigation tab bar with a custom bottom toolbar when a view enters edit mode. Currently, I am using the following code to achieve this:

content    
    .toolbar(isEditing ? .hidden : .visible, for: .tabBar)
.    toolbar(isEditing ? .visible : .hidden, for: .bottomBar)

However, this results in a janky animation. When the bottom bar appears, it animates in above (in contrast to in place of) the tab bar, then "jumps" back down to the correct offset without animation. I had to workaround this by delaying the appearance of bottom bar by 0.3s. I am already using withAnimation().

Is this a bug or am I using the APIs incorrectly? Is there a more seamless way to achieve this switching effect other than delaying the bottom bar? Thanks!

Answered by DTS Engineer in 794633022

@NSCruiser Here's an example of how to go about it:

struct ContentView: View {
    @State private var isEditing = false

    var body: some View {
        NavigationStack {
            TabView {
                Tab("Received", systemImage: "tray.and.arrow.down.fill") {
                    Button("toogle") {
                        isEditing.toggle()
                    }
                    .toolbar(isEditing ? .hidden : .visible, for: .tabBar)
                }
                .badge(2)
                
                Tab("Sent", systemImage: "tray.and.arrow.up.fill") {
                    Color.blue
                }
                
                Tab("Account", systemImage: "person.crop.circle.fill") {
                    Color.green
                }
                .badge("!")
            }
            .toolbar(isEditing ? .visible : .hidden, for: .bottomBar)
            .animation(.easeIn, value: isEditing)
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Text("hello world")
                }
            }
        }
    }
}

@NSCruiser Here's an example of how to go about it:

struct ContentView: View {
    @State private var isEditing = false

    var body: some View {
        NavigationStack {
            TabView {
                Tab("Received", systemImage: "tray.and.arrow.down.fill") {
                    Button("toogle") {
                        isEditing.toggle()
                    }
                    .toolbar(isEditing ? .hidden : .visible, for: .tabBar)
                }
                .badge(2)
                
                Tab("Sent", systemImage: "tray.and.arrow.up.fill") {
                    Color.blue
                }
                
                Tab("Account", systemImage: "person.crop.circle.fill") {
                    Color.green
                }
                .badge("!")
            }
            .toolbar(isEditing ? .visible : .hidden, for: .bottomBar)
            .animation(.easeIn, value: isEditing)
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Text("hello world")
                }
            }
        }
    }
}

@DTS Engineer Thank you for the example. In my app, TabView is the root view, and NavigationStack is nested within each Tab. I changed the provided example to match the structure of my app, and found that the animation issue was still present. Is this expected behavior?

struct ContentView: View {
    @State private var isEditing = false

    var body: some View {
        TabView {
            Tab("Received", systemImage: "tray.and.arrow.down.fill") {
                NavigationStack {
                    Button("toogle") {
                        isEditing.toggle()
                    }
                    .toolbar(isEditing ? .hidden : .visible, for: .tabBar)
                    .toolbar(isEditing ? .visible : .hidden, for: .bottomBar)
                    .animation(.easeIn, value: isEditing)
                    .toolbar {
                        ToolbarItem(placement: .bottomBar) {
                            Text("hello world")
                        }
                    }
                }
            }
            .badge(2)
            
            Tab("Sent", systemImage: "tray.and.arrow.up.fill") {
                Color.blue
            }
            
            Tab("Account", systemImage: "person.crop.circle.fill") {
                Color.green
            }
            .badge("!")
        }
    }
}

I have submitted FB14464408.

After going down a 5am rabbit hole it’s a shame this still isn’t working

How to replace tabBar with bottomBar with smooth animation in SwiftUI?
 
 
Q