How to hide navigation toolbar in SwiftUI using a tabview setup

48 Views Asked by At

When I initially run the application, I have the add button present on the first tab, on the second tab, the add button shouldnt be visible but when I tab back to the first tab, the button is gone. Here is my code for ListView and ContentView. I am trying to figure out a way to use the tags setup to hide the toolbar add button that would automatically update the UI.


struct TaskListView: View {
    
    @ObservedObject var taskStore: TaskStore
    @State private var selectedTab: Tab = .tasks
    
    enum Tab {
        case tasks
        case completed
    }
    
    var body: some View {
        TabView {
            List(taskStore.tasks.filter { !$0.isCompleted }, id: \.self) { task in
                NavigationLink(value: task) {
                    VStack {
                        TaskRowView(task: task)
                    }
                    .padding([.leading, .trailing], 20)
                }
                .navigationDestination(for: Task.self) { task in
                    TaskDetailView(task: $taskStore.tasks
                        .first(where: { $0.id == task.id })!)
                }
            }
            .tabItem {
                Image(systemName: "list.bullet.circle")
                Text("Tasks")
                }
            .tag(Tab.tasks)
            .toolbar(.visible, for: .navigationBar)
            List(taskStore.tasks.filter { $0.isCompleted }, id: \.self) { task in
                NavigationLink(value: task) {
                    VStack {
                        TaskRowView(task: task)
                        }
                    .padding([.leading, .trailing], 20)
                    }
                .navigationDestination(for: Task.self) { task in
                    TaskDetailView(task: $taskStore.tasks
                        .first(where: { $0.id == task.id })!)
                }
            }
            .tabItem {
                Image(systemName: "checkmark.circle")
                Text("Completed")
                }
            .tag(Tab.completed)
            .toolbar(.hidden, for: .navigationBar)
          }
          
        }
    }
    
    struct TaskListView_Previews: PreviewProvider {
        static var previews: some View {
            TaskListView(taskStore: TaskStore())
        }
    }

Contentview file:

import SwiftUI

struct ContentView: View {
  @StateObject var taskStore = TaskStore()
  
  var body: some View {
    NavigationStack {
      VStack {
        if taskStore.tasks.isEmpty {
          Text("No tasks found")
        } else {
          TaskListView(taskStore: taskStore)
        }
        Spacer()
        //NewTaskButton(addingTask: $addingTask)
      }
      .navigationTitle("My Tasks")
      .toolbar {
        ToolbarItem(placement: .navigationBarTrailing) {
    
                NewTaskButtonView(taskStore: taskStore)
            
         
        }
      }
    }
  }
  
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
1

There are 1 best solutions below

0
On BEST ANSWER

The TabBar should always be on top of the view hierarchy.

                    TabView
                   /       \
            Navigation   Navigation
                |            |
               List1        List2

Following your requirements, I would prefer to refactor your code as below.

Firstly, break into two lists, IncompleteTaskView and CompletedTaskView. You're using taskStore for displaying purpose only so I will use normal variable. You may need to change to @Enviroment object later if needed.

struct IncompleteTaskView: View {
  var taskStore: TaskStore

  var body: some View {
    NavigationStack {
      VStack {
        ...
      }
      .navigationTitle("Incomplete Tasks")
      .toolbar {
        ToolbarItem(placement: .navigationBarTrailing) {
          NewTaskButtonView(taskStore: taskStore)
        }
      }
    }
  }
}

The same implementation with CompletedTaskView, except .toolBar.


Secondly, the ContentView will have TabView only:

struct ContentView: View {
  ...
  @StateObject private var taskStore = TaskStore()
  
  var body: some View {
    TabView(selection: $selectedTab) {
      IncompleteTaskView(taskStore: taskStore)
        .tabItem {
            Image(systemName: "list.bullet.circle")
            Text("Tasks")
        }
        .tag(Tab.tasks)

      CompletedTaskView(taskStore: taskStore)
        .tabItem {
            Image(systemName: "checkmark.circle")
            Text("Completed")
        }
        .tag(Tab.completed)
      }
    }
  }
}