简体   繁体   中英

SwiftUI how to hide navigation bar with TabView

I'm using SwiftUI TabView inside NavigationView , But I just can't hide the navigation bar in iOS 13.0 simulator.

Here is the code:

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

}

Any help? thanks!

在此处输入图像描述

you have already hide the navigation bar with .navigationBarHidden(true) . here you are seeing the safe area , so you can let your view expand in to the safe area by using .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
                        })
            }
            
        }
    }
}

在此处输入图像描述 在此处输入图像描述

In the View you want to hide the NavigationView use .navigationBarHidden(true) to hide it.

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

If you don't want the big NavigationView, use .navigationBarTitleDisplayMode(.inline) to shrink the size, and also keep using ToolBarItems .

Check this

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

I think it's system bug. I had same problem.

同样的问题

Here is my Solution

1. Add UIApplication extension

https://stackoverflow.com/a/30858591/12496427

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. Using it in onAppear() function

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

        }
    }
}

If you get access to the boolean that sets whether or not you are showing your navigation bar, you can fix this issue. But its not pleasant - I think there must be a bug behind the issue here.

The NavigationView that contains the TabView has a modifier that governs if the nav bar shows. Something like this:

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)

Ive put that property ( initialNavBarHidden ) within my NavState class, which is an object that contains all the nav links etc for my entire app navigation. That object is placed in the @environment so i can use it anywhere.

On the .onAppear for each tab, if I set that property to false, and then true, using DispatchQueue.main.asyncAfter.. with a short gap between them, then the problem is fixed. As I say, its a hack, but it works. I could get nothing else to work after some days looking at this issue.

So I have a function on my navState class like this:

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

And I call it for onAppear for each tab page, eg:

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

You get a tiny visual glitch, which is horrible but brief. As a better fix Im actually going to take my tab bar out of the NavigationView altogether, as thats where the bug happens.

How about the negative padding trick?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM