Hide the TabBar while navigating between screens in Xcode Swift for iOS 16 or later.

Hey, I am developing my app in Swift using Xcode for iOS 16 or later. I want to implement the navigation behavior found in apps like WhatsApp or Instagram, where navigating from the feed to a user's profile keeps the tab bar visible. Then, when opening a chat from the profile, a new view appears, leaving the profile view behind along with the tab bar.

I have this code as a base to achieve this, but when navigating from View 1 to View 2, it applies the effect that should only happen in View 3. I haven't been able to prevent View 2 from using this effect and limit it only to View 3. Can anyone help me???


import SwiftUI

struct ContentView: View {
    @State private var path: [String] = [] // Controls the navigation stack in View1

    var body: some View {
        NavigationStack(path: $path) {
            TabView {
                View1(path: $path)
                    .tabItem {
                        Label("View 1", systemImage: "1.circle")
                    }

                View4()
                    .tabItem {
                        Label("View 4", systemImage: "4.circle")
                    }
            }
            .navigationDestination(for: String.self) { value in
                if value == "View3" {
                    View3(path: $path) // View3 outside the TabView
                }
            }
        }
    }
}

struct View1: View {
    @Binding var path: [String]

    var body: some View {
        VStack {
            Text("View 1 with TabBar")
            Button("Go to View 2") {
                path.append("View2") // Adds View2 to the stack
            }
        }
        .navigationDestination(for: String.self) { value in
            if value == "View2" {
                View2(path: $path)
            }
        }
    }
}

struct View2: View {
    @Binding var path: [String]

    var body: some View {
        VStack {
            Text("View 2 with TabBar")
            Button("Go to View 3 (Without TabBar)") {
                path.append("View3") // Adds View3 to the stack
            }
        }
    }
}

struct View3: View {
    @Binding var path: [String]

    var body: some View {
        VStack {
            Text("View 3 without TabBar")
                .font(.largeTitle)
                .padding()

            Button("Go Back") {
                path.removeLast() // Returns to View2
            }
        }
    }
}

struct View4: View {
    var body: some View {
        Text("View 4 with TabBar")
    }
}

@marcperezg

I can't speak on how those Apps implement that flow, but the general way for this doing is to put the NavigationStack inside each tab and keeping you TabView as your top level navigation container.

I found a way to achieve what I meant to achieve, but I don't think it's the best way to do it. However, I haven't found any other solution, so if anyone has any tips, I'd really appreciate it! Hahaha.

import SwiftUI

struct ContentView: View {
    @State private var path = NavigationPath() // Manages global navigation

    var body: some View {
        NavigationStack(path: $path) { // Moves NavigationStack outside of TabView
            TabView {
                ListView(path: $path)
                    .tabItem {
                        Label("List", systemImage: "list.bullet")
                    }

                GreenView()
                    .tabItem {
                        Label("Green", systemImage: "leaf.fill")
                    }
            }
            .navigationDestination(for: String.self) { value in
                if value == "ExtraDetailView" {
                    ExtraDetailView()
                }
            }
        }
    }
}

struct ListView: View {
    @State private var selectedItem: String?
    @Binding var path: NavigationPath // Receives global navigation

    let items = ["Item 1", "Item 2", "Item 3"]

    var body: some View {
        NavigationSplitView {
            List(items, id: \.self, selection: $selectedItem) { item in
                Text(item)
                    .onTapGesture {
                        selectedItem = item
                    }
            }
            .navigationTitle("List")
        } detail: {
            if let selectedItem = selectedItem {
                DetailView(item: selectedItem, path: $path)
            } else {
                Text("Select an item")
            }
        }
    }
}

struct DetailView: View {
    let item: String
    @Binding var path: NavigationPath // Uses global navigation

    var body: some View {
        VStack {
            Text("Details of \(item)")

            Button("See more details") {
                path.append("ExtraDetailView") // Pushes the view on top of the TabView
            }
        }
        .navigationTitle("Details")
    }
}

struct ExtraDetailView: View {
    var body: some View {
        Text("Additional information")
            .navigationTitle("More details")
    }
}

struct GreenView: View {
    var body: some View {
        NavigationSplitView {
            NavigationLink("Go to YELLOW View", destination: YellowView())
                .buttonStyle(.borderedProminent)
        } detail: {
            YellowView()
        }
    }
}

struct YellowView: View {
    var body: some View {
        Color.yellow
            .ignoresSafeArea()
            .overlay(
                Text("Yellow View")
                    .font(.largeTitle)
                    .foregroundColor(.white)
            )
    }
}```

Hide the TabBar while navigating between screens in Xcode Swift for iOS 16 or later.
 
 
Q