How to hide TabBar while keeping tab navigation functional in SwiftUI?

67 Views Asked by At

I have a SwiftUI setup where I'm using a TabView for navigation between different views. In larger screen sizes (width > 900), I've implemented a side menu using an HStack to provide a more convenient way of switching tabs. However, in this setup, I want to hide the tab bar that's normally used for navigation between tabs, while still keeping the tab navigation functional.

Here's a simplified version of my code:

    
    // Other code...
    
    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 0) {
                if geometry.size.width > 900 {
                    // Side menu implementation...
                }
                TabMenuView(activeTab: $route)
                    .frame(maxWidth: .infinity)
                    .toolbar(.hidden, for: .tabBar) // This only works, outside the root of a nvaigation stack
            }
        }
    }
}

struct TabMenuView: View {
    
    // Other code...
    
    var body: some View {
        TabView(selection: $activeTab) {
            // Tab items...
        }
    }
}

I tried a lot, but I just can't hide the TabBar, without hiding the whole TabView. It work's, when a view is pushed to a NavigationStack with the .toolbar(.hidden, for: .tabBar), but thats not the behavior I am hoping for.

1

There are 1 best solutions below

2
CouchDeveloper On BEST ANSWER

You should maintain the selected tab and use bindings where both UI versions depend on, respectively set it:


import SwiftUI

struct MainView: View {
    
    enum Tabs: String {
        case one
        case two
    }
    
    // @Environment(\.horizontalSizeClass) var horizontalSizeClass
    
    @State private var tabSelection: Tabs = .two

    var body: some View {
        GeometryReader { geometry in
            if geometry.size.width <= 900 {
                TabView(selection: $tabSelection) {
                    ContentView()
                    .tabItem {
                        Label(Tabs.one.rawValue, systemImage: "1.square")
                    }
                    .tag(Tabs.one.rawValue)

                    OtherView()
                    .tabItem {
                        Label(Tabs.two.rawValue, systemImage: "2.square")
                    }
                    .tag(Tabs.two.rawValue)
                }
            } else {
                // use Custom Menu
                VStack {
                    switch tabSelection {
                    case .one:
                        HStack {
                            Button("Show Tab 2") {
                                tabSelection = .two
                            }
                            Spacer()
                            ContentView()
                        }
                    case .two:
                        HStack {
                            Button("Show Tab 1") {
                                tabSelection = .one
                            }
                            Spacer()
                            OtherView()
                        }
                    }
                }
            }

        }
    }
    
}

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

struct OtherView: View {
    var body: some View {
        VStack {
            Text("Other view")
        }
        .padding()
    }
}


#Preview {
    MainView()
}

Note: you may use Size Classes to determine the layout and UI.