0

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 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

2 Comments

This would work for some use cases. In my case I want to keep the state of the children NavigationStack, when rotating the device, but still swap between Tab- and Sidebar Navigation.
@MariusBonifer You didn't mention anything keeping the navigation stack in your sample. However, it works the same: navigation is a function of state. Just keep the state and pass it to the child view. I would suggest to ask another question, if you have trouble with a navigation stack or other things. ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.