Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hiding new tab view in iOS 18 when pushing screens

With iOS 18 Apple decided to move our beloved bottom tab bar controller to the top of the screen (apparently thats more modern). I am having the following situation: I have TabView where we have root screen FirstView, which has a button wrapped in NavigationStack. When tapping on the button we push a second view where we want the tab bar hidden. However because the first screen has a title when pushing the view jumps.

https://imgur.com/a/TdYwqZp

Here is the code:

struct ContentView: View {
    @State var path: [String] = []
    @State var hideTabBar: Bool = false

    var body: some View {
        TabView {
            navigationStack
                .tabItem {
                    Text("Eng")
                }
            placeholderStack
                .tabItem {
                    Text("Span")
                }
        }
    }

    var navigationStack: some View {
        NavigationStack(path: $path) {
            Text("First View")
                .navigationTitle("English View")
                .navigationDestination(for: String.self) {
                    Text($0)
                        .toolbar {
                            ToolbarItem(placement: .principal) {
                                Text("Second View")
                            }
                        }
                }
                .onTapGesture {
                    hideTabBar = true
                    path.append("Second View")
                }
                .onAppear {
                    hideTabBar = false
                }
                .toolbar {
                    ToolbarItem(placement: .principal) {
                        Text("Top Bar")
                    }
                }
                .toolbar(hideTabBar ? .hidden : .visible, for: .tabBar)
        }
    }
    
    var placeholderStack: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hola, mundo")
        }
        .padding()
    }
}

like image 610
Boyan Pavlov Avatar asked Sep 02 '25 04:09

Boyan Pavlov


1 Answers

When navigating to the child view, it works better if the tab bar is hidden first, then navigation is performed afterwards. This can be done by setting the flag using withAnimation and then performing the navigation in a completion callback.

For navigating back, the transition can be made a bit smoother by resetting the flag for hiding the tab bar in .onDisappear for the child view, with animation:

Text("First View")
    .navigationTitle("English View")
    .navigationDestination(for: String.self) {
        Text($0)
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Text("Second View")
                }
            }
            .onDisappear {
                withAnimation {
                    hideTabBar = false
                }
            }
    }
    .onTapGesture {
        withAnimation {
            hideTabBar = true
        } completion: {
            path.append("Second View")
        }
    }
    .toolbar {
        ToolbarItem(placement: .principal) {
            Text("Top Bar")
        }
    }
    .toolbar(hideTabBar ? .hidden : .visible, for: .tabBar)

Animation


Another way of navigating back is to replace the native back button with a custom one. This allows the flag for the tab bar to be reset first, then navigation can be performed afterwards, like before.

This approach avoids the staggered animation when navigating back. However, you lose the effect of the large navigation title morphing into the back button. It also seems to be important to set .navigationBarTitleDisplayMode(.large), otherwise the navigation title doesn't show when returning to the parent view.

Text("First View")
    .navigationBarTitleDisplayMode(.large)
    .navigationTitle("English View")
    .navigationDestination(for: String.self) {
        Text($0)
            .navigationBarBackButtonHidden()
            .toolbar {
                ToolbarItem(placement: .navigation) {
                    Button {
                        withAnimation {
                            hideTabBar = false
                        } completion: {
                            path.removeLast()
                        }
                    } label: {
                        HStack {
                            Image(systemName: "chevron.left")
                                .fontWeight(.semibold)
                                .imageScale(.large)
                            Text("English View")
                        }
                    }
                }
                ToolbarItem(placement: .principal) {
                    Text("Second View")
                }
            }
    }
    .onTapGesture {
        withAnimation {
            hideTabBar = true
        } completion: {
            path.append("Second View")
        }
    }
    .toolbar {
        ToolbarItem(placement: .principal) {
            Text("Top Bar")
        }
    }
    .toolbar(hideTabBar ? .hidden : .visible, for: .tabBar)

Animation

like image 62
Benzy Neez Avatar answered Sep 04 '25 21:09

Benzy Neez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!