最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

swift - Hiding new tab view in iOS 18 when pushing screens - Stack Overflow

programmeradmin4浏览0评论

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.

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()
    }
}

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/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()
    }
}

Share Improve this question asked Mar 25 at 12:33 Boyan PavlovBoyan Pavlov 2302 silver badges11 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 3

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)


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)

发布评论

评论列表(0)

  1. 暂无评论