8

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!

enter image description here

William Hu
  • 15,423
  • 11
  • 100
  • 121

8 Answers8

5

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("")
    }
Thomas Paul
  • 355
  • 5
  • 13
  • Hi Thomas, it did work for me but I am having an issue and need your help in that. I am using navigation link to reach the *tab view** screen and when I reach the *tabview* screen, it is still getting the top space but if I **directly opens** the tab view your *solution* works fine. So, can you tell any solution in which if someone is coming from a different view to tab view, it should not take the top space – Taimoor Arif May 16 '22 at 09:35
  • 2
    This works on the first display tab, switch tab and top spaces displayed. I think we should use a custom tab view. I tried many ways but not work. – Binh Ho Jul 15 '22 at 04:44
2

I was having the same problem.Even though I decorated each View with .navigationBarHidden(true).navigationBarTitle(""), the top space was not hidden when I moved from another View to TabView on iOS 15 series.

So I tried the following method, and the top space is hidden correctly even when moving from another View to TabView.

The following is a simple sample.

@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) was applied to the first view of the TabView, and after a delay, it was set to true.

Since it flickers for a moment when it is displayed, it will be displayed nicely if you use Animation when displaying the RootView.

It may seem a bit aggressive, but it works fine in my project.

4b0
  • 21,981
  • 30
  • 95
  • 142
1

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

Same issue

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

        }
    }
}
Harry Kim
  • 699
  • 6
  • 11
1

To fix for iOS 15, just set 3 properties (navigationBarTitle, navigationBarBackButtonHidden and navigationBarHidden) as below:

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

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

Make sure you don't set these properties inside HomeView() or SettingView(),...

Kha Nguyen
  • 11
  • 3
0

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.

Yuto
  • 658
  • 2
  • 8
  • 20
0

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.

Luke Smith
  • 1,218
  • 12
  • 17
-1

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

enter image description here enter image description here

YodagamaHeshan
  • 4,996
  • 2
  • 26
  • 36
  • Hi That's iOS 14 api, I am running on iOS 13. And not that safe area but the navigation bar, check the image on the question above. – William Hu Feb 24 '21 at 03:02
  • Are you getting this problem only with iOS 13 not with iOS 14? cause I have run on iOS 14 and it gave me this result. – YodagamaHeshan Feb 24 '21 at 03:08
-1

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
    }
  }
}
蘇哲聖
  • 735
  • 9
  • 17