How to hide TabView when opening a new view with NavigationLink?

648 views Asked by At

Assuming we have a SwiftUI view containing

struct ContentView: View {
    var body: some View {
        TabView {
            FirstView().tabItem {
                // tabItem image and text
            }
            SecondView().tabItem {
                // tabItem image and text
            }
        }
    }
}

Now, let's say FirstView contains a NavigationView with scrollable content using NavigationLink for each element. How can I make it such that when a NavigationLink destination is triggered (i.e. a child view is opened), that it takes over the whole page (in full-screen) and thus hides the TabView?

Ideally I would like to support iOS 13+.

I have tried to follow the guidance at Hacking with Swift but to no avail.

I also followed the advice in SwiftUI Hide TabView bar inside NavigationLink views but found that the top solution is not so performant, so I am hoping to achieve a solution without a delayed appearance.

2

There are 2 answers

0
dsynkd On BEST ANSWER

Enclose the contents of your tabitem inside an if condition that checks a shared state:

struct ContentView: View {

    @StateObject private var state = State()

    var body: some View {
        TabView {
            FirstView().tabItem {
                if !state.hideTabView {
                    // tabItem image and text
                }
            }
            SecondView().tabItem {
                if !state.hideTabView {
                    // tabItem image and text
                }
            }
        }
        .environmentObject(state)
    }
}

Where State is an ObservableObject as such:

class State: ObservableObject {
    @Published hideTabView: Bool = false
}

Then you can use onAppear on the View that is linked to via NavigationLink (e.g inside FirstView):

struct FirstView: View {
    
    @EnvironmentObject private var state: State
    var body: some View {
        VStack {
            // ... some content
        }
        .onAppear(perform: { state.hideTabView = true })
        .onDisappear(perform: { state.hideTabView = false })
    }
}

There is a slight delay on the TabView appearing again when you press "< Back", if that really bothers you then you can make a custom Back button and move this state.hideTabView = false to the event of tapping that button.

That is one approach I can think of :) Also, you might find this thread helpful.

0
Ryan Pierce On

One solution is to remove your NavigationView from your child views (FirstView and SecondView) and place a single NavigationView outside of your TabView.

NavigationView {
    TabView {
        //...
    }
}

This appropriately puts your TabView in the navigation stack rather than it being the parent to a navigation stack. This may have undesired outcomes including navigationBar title and UI changes since you are moving the root of the navigation stack upstream, however this worked for my use case.