SwiftUI如何在TabView中隐藏导航栏

9

我正在使用SwiftUI中的TabView嵌套在NavigationView中,但是在iOS 13.0模拟器中无法隐藏导航栏。

这是代码:

import SwiftUI

struct TestView: View {
    var body: some View {
        ZStack {
            Color.green
            Text("Hello")
        }
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            ZStack {
                Color.red
                TabView(selection: .constant(0),
                        content: {
                            TestView()
                                .tabItem { Text("test") }
                                .tag(0)
                                .navigationBarTitle("")
                                .navigationBarHidden(true)
                        })
            }

        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }

}

需要帮忙吗?谢谢!

在此输入图片描述


我在iOS15中遇到了同样的问题。 - Harry Kim
有找到任何解决方案吗? - Gokul G
8个回答

5

请检查此内容

TabView {
        ECHomeView().tabItem {
            VStack {
                Text("Home")
                Image.Home.renderingMode(.template)
            }
        }.navigationBarHidden(true)
        ECMyClaimsView().tabItem {
            VStack {
                Text("My Claims")
                Image.Myclaims.renderingMode(.template)
            }
        }.navigationBarHidden(true).navigationBarTitle("")
        ECAddClaimView().tabItem {
            VStack {
                Text("Create")
                Image.Create.renderingMode(.template)
            }
        }.navigationBarHidden(true).navigationBarTitle("")
        ECMyApprovalsView().tabItem {
            VStack {
                Text("My Approvals")
                Image.MyApprovals.renderingMode(.template)
            }
        }.navigationBarHidden(true).navigationBarTitle("")
        ECMenuView().tabItem {
            VStack {
                Text("Menu")
                Image.Menu.renderingMode(.template)
            }
        }.navigationBarHidden(true).navigationBarTitle("")
    }

嗨Thomas,它对我起作用了,但我遇到了问题,需要你的帮助。我正在使用导航链接到达tab view屏幕,当我到达tabview屏幕时,它仍然获取顶部空间,但如果我直接打开选项卡视图,你的解决方案就可以正常工作。因此,你能告诉我任何解决方案吗?如果有人从不同的视图进入选项卡视图,它不应该占用顶部空间。 - Taimoor Arif
3
这个在第一个显示标签上可以工作,但切换标签和顶部空间时无法正常显示。我认为我们应该使用自定义标签视图。我尝试了很多方法,但都没有成功。 - Binh Ho

2

我遇到了同样的问题。虽然我使用.navigationBarHidden(true).navigationBarTitle("")修饰了每个视图,但当我从另一个视图移动到iOS 15系列上的TabView时,顶部空间仍然没有隐藏。

因此,我尝试了以下方法,即使从另一个视图移动到TabView,顶部空间也可以正确隐藏。

以下是一个简单的示例。

@State var selectedTab: TestTab = .test1
@State var test1ViewNavigationBarHidden = false
@State var opacity = 0.0

var body: some View {
    ZStack {
        NavigationView {
            TabView(selection: $selectedTab) {
                Test1View()
                    .navigationBarHidden(test1ViewNavigationBarHidden)
                    .navigationBarTitle("")
                    .onAppear{
                        Task {
                            try! await Task.sleep(seconds: UInt64(0.001))
                            test1ViewNavigationBarHidden = true
                        }
                    }
                    .tag(TestTab.test1)

                Test2View()
                    .navigationBarHidden(true).navigationBarTitle("")
                    .tag(TestTab.test2)

                Test3View()
                    .navigationBarHidden(true).navigationBarTitle("")
                    .tag(TestTab.test3)
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
    .opacity(opacity)
    .onAppear {
        withAnimation(.linear(duration: 0.3)) {
            opacity = 1.0
        }
    }
}

.navigationBarHidden(false)被应用于TabView的第一个视图,并在延迟后设置为true。

由于它在显示时会闪烁一下,因此在显示RootView时使用动画可以使其显示得更好。

这可能看起来有点激进,但在我的项目中运行良好。


1
我认为这是系统故障。 我也遇到了同样的问题。

Same issue

这是我的解决方案。
1. 添加UIApplication扩展。

https://dev59.com/_V8d5IYBdhLWcg3wkS7Y#30858591

extension UIApplication {
    class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }
}

2. 在onAppear()函数中使用它

struct TestView: View {
    var body: some View {
        ZStack {
            Color.green
            Text("Hello")
        }
/////// HERE ////////
        .onAppear { 
            UIApplication.topViewController()?
               .navigationController?.isNavigationBarHidden = true
        }
/////// HERE ////////
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            ZStack {
                Color.red
                TabView(selection: .constant(0),
                        content: {
                            TestView()
                                .tabItem { Text("test") }
                                .tag(0)
                                .navigationBarTitle("")
                                .navigationBarHidden(true)
                        })
            }

        }
    }
}

在iOS 15中无法工作。 - Tanvirgeek
我有一个解决方案,适用于iOS 15及以上版本。当每个选项卡出现时,将.tabBarHidden设置为false,然后再设置为true。 - Luke Smith

0
在你想要隐藏 NavigationView 的视图中,使用 .navigationBarHidden(true) 来隐藏它。
struct TestView: View {
    var body: some View {
        ZStack {
            Color.green
            Text("Hello")
        }
        .navigationBarHidden(true)
    }
}

如果您不想要大的NavigationView,请使用.navigationBarTitleDisplayMode(.inline)来缩小大小,并继续使用ToolBarItems


0
如果您可以访问设置是否显示导航栏的布尔值,您可以解决此问题。但这并不愉快 - 我认为这里必须有一个错误。
包含TabView的NavigationView具有修饰符,用于控制导航栏的显示。类似于这样的东西:
NavigationView {
                NavigationLink(destination:
                                TabBarScreen(domainDependencies: domainDependencies).environmentObject(navState),
                               isActive: $navState.initialNavMainLink) {
                    EmptyView()
                }.isDetailLink(false)
            }
            .navigationViewStyle(StackNavigationViewStyle())
            //the property here governs hiding of nav bar:
            .navigationBarHidden(navState.initialNavBarHidden)

我将该属性(initialNavBarHidden)放在了我的NavState类中,这是一个包含整个应用程序导航的所有导航链接等对象的对象。该对象被放置在@environment中,因此我可以在任何地方使用它。

对于每个选项卡的.onAppear,如果我将该属性设置为false,然后使用DispatchQueue.main.asyncAfter ..在它们之间留有短暂的间隔,那么问题就解决了。正如我所说,这是一种hack方法,但它有效。在经过几天的研究后,我无法找到其他解决方法。

因此,我在我的navState类上有一个函数,如下所示:

func tabBarBugFix() {
        DispatchQueue.main.asyncAfter(deadline: .now()) {
            self.initialNavBarHidden = false
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.00001) {
                self.initialNavBarHidden = true
            }
        }
    }

我会为每个选项卡页面调用onAppear,例如:

struct PostPage: View {
    
    @EnvironmentObject var navState: NavState
    
    var body: some View {
        Text("Create a Post")
            .onAppear() {
                navState.tabBarBugFix()
            }
    }
}

你会遇到一个微小的视觉故障,虽然很糟糕但是很短暂。为了更好的修复,我实际上要将我的选项卡栏从NavigationView中移除,因为这就是错误发生的地方。


0

要修复iOS 15的问题,只需按照以下方式设置3个属性(navigationBarTitlenavigationBarBackButtonHiddennavigationBarHidden):

TabView {
    HomeView()
        .tabItem {
            Text("Home")
        }
        .tag(0)
        .navigationBarTitle("")
        .navigationBarBackButtonHidden(true)
        .navigationBarHidden(true)

    SettingView()
        .tabItem {
            Text("Setting")
        }
        .tag(1)
        .navigationBarTitle("")
        .navigationBarBackButtonHidden(true)
        .navigationBarHidden(true)
}

请确保您不要在 HomeView() 或 SettingView() 内设置这些属性,...


-1

负边距技巧怎么样?

struct ContentView: View {
  var body: some View {
    NavigationView {
      TabView {
        List(1 ..< 40, id: \.self) {
          Text("A" + $0.description)
        }.tag(1).navigationBarHidden(true).navigationBarTitleDisplayMode(.inline)
        List(1 ..< 40, id: \.self) {
          Text("B" + $0.description)
        }.tag(2).navigationBarHidden(true).navigationBarTitleDisplayMode(.inline)
      }.padding(.bottom, -50) // <- trick
    }
  }
}

-1

你已经使用 .navigationBarHidden(true) 隐藏了导航栏。在这里,你可以看到 安全区域,所以你可以使用 .ignoresSafeArea() 让你的视图扩展到安全区域。

struct ContentView: View {
    var body: some View {
        NavigationView {
            ZStack {
                Color.red
                
                TabView(selection: .constant(0),
                        content: {
                            TestView()
                                .tabItem { Text("test") }
                                .tag(0)
                                .navigationBarTitle("")
                                .navigationBarHidden(true)
                                .ignoresSafeArea() //<-here
                        })
            }
            
        }
    }
}

enter image description here enter image description here


嗨,那是iOS 14的API,我正在运行iOS 13。并不是安全区域,而是导航栏,请查看上面问题中的图片。 - William Hu
你只在 iOS 13 上遇到这个问题吗?因为我在 iOS 14 上运行它,得到了这个结果。 - YodagamaHeshan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接