Search code examples
swiftuiswiftui-navigationsplitview

SwiftUI ToolbarItem before side bar toggle


I have a simple SwiftUI app, with a simple toolbar. It contains one button which just prints something to the console. However the SwiftUI sidebar toggle that comes with the navigationspliview that it's in is always before the button. How can I change that? I have tried to just remove the sidebar toggle completely, and replace that with a custom one, however when the sidebar is expanded, its is then still in the main view.

So I basically just want to have the button before the sidebar toggle, when the sidebar is NOT expanded.

Visual Example:

Detail + Sidebar
   [TOGGLE] | [X-BUTTON]

Detail, no Sidebar
   | [X-BUTTON] [TOGGLE]

"|" represents the sidebar, aka. the sidebar divider

Here is a minimal example code:


import SwiftUI

struct ProjectView: View {
    var body: some View {
        NavigationSplitView {
            List {
                
            }
        } detail: {
            ZStack {
                
            }
            .toolbar {
                ToolbarItemGroup(placement: .topBarLeading) {
                    Button {
                        print("Close window...")
                    } label: {
                        Image(systemName: "xmark")
                    }
                }
            }
        }
    }
}

Solution

  • The documentation for NavigationSplitView explains how you can...

    programmatically control the visibility of navigation split view columns by creating a State value of type NavigationSplitViewVisibility

    This also lets you determine, whether or not the sidebar is showing.

    So if you disable the default toggle, you can make the visibility of your own toggle button conditional on whether the sidebar is showing or not. Something like:

    struct ProjectView: View {
        @State private var columnVisibility: NavigationSplitViewVisibility = .automatic
    
        var body: some View {
            NavigationSplitView(columnVisibility: $columnVisibility) {
                List {
    
                }
                .toolbar(removing: .sidebarToggle)
            } detail: {
                ZStack {
    
                }
                .toolbar {
                    ToolbarItemGroup(placement: .topBarLeading) {
                        Button {
                            print("Close window...")
                        } label: {
                            Image(systemName: "xmark")
                        }
                        if columnVisibility == .detailOnly {
                            Button {
                                columnVisibility = .doubleColumn
                            } label: {
                                Image(systemName: "sidebar.left")
                            }
                        }
                    }
                }
            }
        }
    }