Greg Ennis
Greg Ennis

Reputation: 15379

NavigationStack inside TabView inside NavigationStack does not work

I want to have a root NavigationStack that lets the user navigate around a SwiftUI app, including to a TabView with tabs that have their own navigation stack. Unfortunately, this seems to not work at all (xcode 14.2, iOS 16).

The following example demonstrates the issue. When you attempt to navigate inside the tab view navigation stack, the tabs disappear and then the app goes into a broken state where navigation basically stops working entirely.

import SwiftUI

struct TabsView: View {
    var body: some View {
        TabView {
            NavigationStack {
                ZStack {
                    NavigationLink("Navigate to child tab", value: 1)
                }
                .navigationDestination(for: Int.self) { screen in
                    Text("Tab child \(screen)")
                }
            }
            .tabItem {
                Label("Screen 1", systemImage: "house")
            }
            
            Text("Screen 2")
                .tabItem {
                    Label("Screen 2", systemImage: "house")
                }
        }
    }
}

struct ContentView: View {
    var body: some View {
        NavigationStack {
            VStack {
                NavigationLink("Show Tabs", value: "tabs")
            }
            .navigationDestination(for: String.self) { screen in
                if screen == "tabs" {
                    TabsView()
                } else {
                    Text("?")
                }
            }
        }
    }
}

How can I make this work?

Upvotes: 3

Views: 1688

Answers (2)

Ivan Barabanshchykov
Ivan Barabanshchykov

Reputation: 171

Found solution for this one!

I am placing "top" NavigationStack with Color.clear initial view right after TabView in ZStack.

ZStack {
    tabBarView
        .zIndex(0)
    
    NavigationStack(path: $coordinator.topPath) {
        Color.clear
            .navigationDestination(for: CoordinatorService.Step.self) { destination in
                coordinator.resolve(pathItem: destination)
            }
    }
    .zIndex(1)
    .allowsHitTesting(!coordinator.topPath.isEmpty)
    .introspect(.navigationStack, on: .iOS(.v16, .v17)) {
        $0.viewControllers.forEach { controller in
            controller.view.backgroundColor = .clear
        }
    }
}
.environmentObject(coordinator)

We have to use Introspect library to remove that's NavigationStack's white background, because SwiftUI don't bring that possibility.

Also I am disabling hit testing on top navigation view when there are no views on top.

Check out full example project here:

https://github.com/thekingofsofa/TabNavigationStack/tree/main

EDIT 28.08.24:

We can now remove Introspect library and use ".containerBackground(.clear, for: .navigation)" in iOS 18 to have invisible background for top NavigationStack.

Upvotes: 0

Andrew Mironenko
Andrew Mironenko

Reputation: 1

Use NavigationView in ContentView. Apple has problems with NavigationStack in hierarchy of NavigationStack.

Upvotes: 0

Related Questions