UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: How to use different toolbars for each tab view inside a NavigationSplitView?

Forums > SwiftUI

I'm using a NavigationSplitView with two columns (SidebarView and ContentView) and a detail view that is a TabView. I want each of the tab views (here, Bingo and Bongo) to have different toolbars but I'm tying myself in knots.

Currently I can present a toolbar for the first tab but it doesn't change when the second tab is selected. Even if it did correctly change the toolbar I wouldn't be happy adding the toolbar inside the NavigationSplitView (as happens right now) since I'd have problems executing the button methods properly for each of the intended tab views.

Has anyone faced this kind of problem? I know that nesting NavigationViews isn't the way forward so I'm steering clear of that but I'm at the hair pulling stage of debugging.

import SwiftUI

@main
struct YardstickApp: App {
    @State private var selectedTab: String = "Bingo"
    var body: some Scene {
        WindowGroup {
            NavigationSplitView {
                SidebarView()
            } content: {
                ContentView()
            } detail: {
                TabsView(selectedTab: $selectedTab)
                // Add toolbar to the detail view
                .toolbar {
                    switch selectedTab {
                    case "Bingo":
                        ToolbarItem(placement: .navigationBarLeading) {
                            Button("Settings") { }
                        }
                    default:
                        ToolbarItem(placement: .navigationBarLeading) {
                            Button("Filter") { }
                        }
                    }
                }
            }
        }
    }
}

struct SidebarView: View {
    var body: some View { Text("SidebarView") }
}

struct ContentView: View {
    var body: some View { Text("ContentView") }
}

struct TabsView: View {
    @Binding var selectedTab: String
    var body: some View {
        VStack {
            TabView(selection: $selectedTab) {
                BingoView().tag(BingoView.tag)
                    .tabItem {
                        Image(systemName: "rectangle.and.pencil.and.ellipsis")
                        Text("Bingo")
                    }
                BongoView().tag(BongoView.tag)
                    .tabItem {
                        Image(systemName: "list.bullet")
                        Text("Bongo")
                    }
            } // TabView - end
        } // VStack - end
    }
}

struct BingoView: View {
    static let tag: String? = "Bingo"
    var body: some View { Text("BingoView") }
}

struct BongoView: View {
    static let tag: String? = "Bongo"
    var body: some View { Text("BongoView") }
}

2      

Hi. I just refactored your code to use enums instead of strings. Seems like now it works without a hitch.

enum SelectedTab {
    case bingo
    case bongo
}

@main
struct TestApp: App {
    @State private var selectedTab = SelectedTab.bingo
    var body: some Scene {
        WindowGroup {
            NavigationSplitView {
                SidebarView()
            } content: {
                ContentView()
            } detail: {
                    TabsView(selectedTab: $selectedTab)
                    // Add toolbar to the detail view
                        .toolbar {
                            switch selectedTab {
                            case .bingo:
                                ToolbarItem(placement: .navigationBarLeading) {
                                    Button("Settings") { }
                                }
                            case .bongo:
                                ToolbarItem(placement: .navigationBarLeading) {
                                    Button("Filter") { }
                                }
                            }
                        }

            }
        }
    }
}

struct TabsView: View {
    @Binding var selectedTab: SelectedTab
    var body: some View {
        VStack {
            TabView(selection: $selectedTab) {
                BingoView().tag(BingoView.tag)
                    .tabItem {
                        Image(systemName: "rectangle.and.pencil.and.ellipsis")
                        Text("Bingo")
                    }
                BongoView().tag(BongoView.tag)
                    .tabItem {
                        Image(systemName: "list.bullet")
                        Text("Bongo")
                    }
            } // TabView - end
        } // VStack - end
    }
}

struct BingoView: View {
    static let tag = SelectedTab.bingo
    var body: some View {
            Text("BingoView")

    }
}

struct BongoView: View {
    static let tag = SelectedTab.bongo
    var body: some View {
            Text("BongoView")
    }
}

2      

@ygeras - I won't pretend I understand why that change works but many thanks for that! Now that it works I've moved it into the TabsView and by passing @State/@Binding can trigger the appropriate method in each of the tabs. Happy days and thanks again.

2      

The issue was here

struct BingoView: View {
    static let tag: String? = "Bingo"
    var body: some View { Text("BingoView") }
}

struct BongoView: View {
    static let tag: String? = "Bongo"
    var body: some View { Text("BongoView") }
}

you indicated tag to be optional. If you change them to String this will work as expected as well.

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.