'Placing the toggle sidebar button on the sidebar toolbar

I have a three column layout macOS application with the first being the sidebar. I have a button that toggles that enabling the user to hide the sidebar.

On Xcode and other macOS, the toggle sidebar button resides on the toolbar on top of the sidebar, and becomes part of the main toolbar when the sidebar is hidden.

For example, open sidebar on Xcode:

enter image description here

And when you hide the sidebar:

enter image description here

I have added the toolbar with the toggle sidebar to the view containing my sidebar, and another toolbar to the second column, but still toggle sidebar appears on the main toolbar, on top of the second column.

Am I missing anything? Here's the code:

    // sidebar view, first of three columns
    struct ContentView: View {
       @State var selection: Set<Int> = [0]
       var body: some View {
          NavigationView {
              List(selection: self.$selection) {
                    NavigationLink(destination: AllData()) {
                        Label("All Data", systemImage: "note.text")
                    }
                    .tag(0)
                    Label("Trash", systemImage: "trash")
                }
                .listStyle(SidebarListStyle())
                .toolbar {
                    ToolbarItem(placement: .navigation) {
                        Button(action: toggleSidebar, label: {
                                Image(systemName: "sidebar.left") }).help("Toggle Sidebar")
                    }
                }
          }
       }
       func toggleSidebar() {
            NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
        }
    }

// second column view, with the rest of the toolbar
struct AllData: View {
   var body: some View {
       NavigationView {
           List(filteredData) {
                // list items here.
           }
           .toolbar {
             ToolbarItem(placement: .automatic) {
                Button("Press Me") {
                    print("Pressed")
                }
             }
             ToolbarItem(placement: .automatic) {
                Button("Press Me too") {
                    print("Pressed too")
                }
             }
         }
       }           
   }
}


Solution 1:[1]

try this:

 ToolbarItem(placement: .primaryAction) {

enter image description here

Solution 2:[2]

If you use the .frame modifier on the sidebar then you are able to set constraints for minimum width, ideal width and maximum width.

I find a minWidth: 148 ensures the sidebar cannot be collapsed to the point where SwiftUI shuffles the toolbar button off to the trailing edge of the nav toolbar and behind (need to click) the double chevron expander.

So your code might look like this...

    ...
    var body: some View {
        NavigationView {
            List(selection: self.$selection) {
                NavigationLink(destination: AllData()) {
                    Label("All Data", systemImage: "note.text")
                }
                .tag(0)
                Label("Trash", systemImage: "trash")
            }
            .listStyle(.sidebar) //<-- from iOS 14 and macOS 10.15
            .frame(minWidth: 148, idealWidth: 160, maxWidth: 192, maxHeight: .infinity)
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button(action: {
                        toggleSidebar
                    }, label: {
                        Image(systemName: "sidebar.left") 
                    })
                    .help("Toggle Sidebar")
                }
            }
      }
   }
   ...

PS. I note that the .primaryAction and .status modifiers both place the sidebar button in a similar position, although I've not tested this thoroughly or completed any research.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2