skip to Main Content

I want to hide TabView bottom TabBar if user navigate from next screen.

For example I have TabView that have two tabItem let’s say Home and Account and home screen have notification option if user click notification I want to navigate to notification screen at the same time I want to hide TabView bottom Tab also. Is Any way to achieve this. I can’t find any direct SwiftUI way to achieve this.

import SwiftUI

struct MyRootScreen: View {
    var body: some View {
        TabView {
            NavigationView {
                HomeScreen()
            }
            .tabItem {
                Image(systemName: "house")
            }
            
            Text("Account")
                .tabItem {
                    Image(systemName: "person")
                }
        }
    }
}


struct HomeScreen: View {
    @State private var showNotification: Bool = false
    
    var body: some View {
        VStack {
            Button {
                showNotification = true
            } label: {
                Text("Show Notification")
            }
        }
        .overlay {
            NavigationLink("", isActive: $showNotification) {
                Text("Notification Screen")
            }
        }
    }
}

Note: I want to to achieve this without wrapping TabView into NavigationView.

2

Answers


  1. It would be better to move the notification screen to your root view and pass the boolean flag as binding that will control notifications.

    Or even better: since your child views will need to only open notifications, and never hide, you can pass a function instead of a binding. It can also be passed in the environment, but be careful with retain cycles.

    Here is an example. If you don’t need Notifications to take the full screen, replace fullScreenCover with sheet:

    import SwiftUI
    
    struct MyRootScreen: View {
        @State private var showNotification: Bool = false
        
        var body: some View {
            TabView {
                NavigationView {
                    HomeScreen(openNotifications: openNotifications)
                }
                .tabItem {
                    Image(systemName: "house")
                }
                
                Text("Account")
                    .tabItem {
                        Image(systemName: "person")
                    }
            }
            .fullScreenCover(isPresented: $showNotification) {
                NavigationView {
                    Text("Notification Screen")
                        .toolbar {
                            ToolbarItem(placement: .navigationBarTrailing) {
                                Button {
                                    showNotification = false
                                } label: {
                                    Text("Close")
                                }
                            }
                        }
                }
            }
        }
        
        private func openNotifications() {
            showNotification = true
        }
    }
    
    
    struct HomeScreen: View {
        let openNotifications: () -> Void
        
        var body: some View {
            VStack {
                Button {
                    openNotifications()
                } label: {
                    Text("Show Notification")
                }
            }
        }
    }
    
    Login or Signup to reply.
  2. So all of the possible ways have been shared above. But i am just concluding them in a single answer and also adding my suggestion too.

    1. fullScreenCover, How your app is following the navigation experience you can utilize this way.
    2. Embedding the Tabview inside Navigationview is another option if your deployment target is iOS 14.0, But if you can use 16.0 you can try . toolbar API to hide the tabview
    3. So changing your rootview on window is also an option you will not have tabview with that view but for that you have to provide a animation to your view when its being replaced on window with your push/pop animation, But the overall experience you may lost with this approach like having back button etc, than you have to be responsible for everything like giving a back button its action etc,.

    Here are the more details for all of three approaches.

    Option 1st is the best way to preset a modal or sheet and show your notification view over there, But it totally depend upon your navigations style or other requirements in your app.

    Using option 2nd which is recommended one, you can go ahead but if you are only on iOS 14.0 with 16.0 you can try the apis provided by apple itself.

    Using option 3rd its possible but you have to manage everyting by your own on that view, like giving a back button, nav title and its actions etc,

    If you want to see some sample code here is the below for 3rd approach.

    import SwiftUI
    
    struct ContentView: View {
        @State private var selectedTab = 0
        @EnvironmentObject var viewSwitch: ViewSwitch
    
        var body: some View {
            if viewSwitch.showRoot == .Tabbed {
                TabView(selection: $selectedTab) {
                    AccountView()
                        .environmentObject(viewSwitch)
                        .tabItem {
                            Label("Account", systemImage: "person")
                        }
                        .tag(0)
    
                    GeneralView()
                        .tabItem {
                            Label("General", systemImage: "gear")
                        }
                        .tag(1)
                }
               
            }
            if viewSwitch.showRoot == .WithoutTabbed {
                NotificationsView()
                    .transition(.move(edge: .trailing))
            }
        }
    }
    
    struct AccountView: View {
        @State private var showNotifications = false
        @State private var isActive = false
        @EnvironmentObject var viewSwitch: ViewSwitch
    
        var body: some View {
            NavigationView {
                VStack {
                    Text("Account View")
                        .font(.largeTitle)
                        .padding()
    
                    Button("Go to Notifications") {
                        showNotifications = true
                        withAnimation(Animation.easeInOut(duration: 0.5)) {
                            viewSwitch.changeRootView(to: .WithoutTabbed)
                        }
                        
                    }
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(10)
                    .padding()
                }
            }
        }
    }
    
    struct GeneralView: View {
        var body: some View {
            VStack {
                Text("General View")
                    .font(.largeTitle)
                    .padding()
            }
        }
    }
    
    struct NotificationsView: View {
        var body: some View {
            NavigationView {
                VStack {
                    Text("Notification view")
                        .font(.largeTitle)
                        .padding()
                }
                .navigationBarTitle("Notification", displayMode: .large)
            }
        }
    }
    
    @main
    struct TestStackOverFlowApp: App {
        let viewSwitch =  ViewSwitch()
        
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .environmentObject(viewSwitch)
            }
        }
    }
    
    
    enum WindowRoot {
        case Tabbed
        case WithoutTabbed
    }
    
    
    class ViewSwitch: ObservableObject {
        public init() {}
    
        @Published public var showRoot: WindowRoot = .Tabbed
        public func changeRootView(to root: WindowRoot) {
            showRoot = root
        }
    }
    

    Attaching a working video of it. Result video
    I hope it helps
    It’s working for me on Xcode 14.3.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search