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      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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.