Toggle Sidebar in Swiftui Navigationview on MACos

Toggle Sidebar in SwiftUI NavigationView on macOS

Since macOS Big Sur beta 4 you can add default sidebar commands with SwiftUI 2.0.

var body: some Scene {
WindowGroup {
NavigationView {
Group {
SidebarView()
ContentView()
}
}
}
.commands {
SidebarCommands()
}
}

This code will add the "Toggle Sidebar" shortcut:

Sample Image

SidebarView code:

var body: some View {
List {
ForEach(0..<5) { index in
Text("\(index)")
}
}
.listStyle(SidebarListStyle())
}

Placing the toggle sidebar button on the sidebar toolbar

try this:

 ToolbarItem(placement: .primaryAction) {

Sample Image

SwiftUI: Get sidebar isCollapsed state on macOS

The idea is to find NSSplitViewController (which is still used internally as engine) and subscribe to observe its first split item (which is our sidebar) isCollapsed state.

Tested with Xcode 13.3 / macOS 12.2.1

demo

Here is main part:

  // find split view through hierarchy
while sview != nil, !sview!.isKind(of: NSSplitView.self) {
sview = sview?.superview
}
guard let sview = sview as? NSSplitView else { return }

controller = sview.delegate as? NSSplitViewController // delegate is our controller
if let sideBar = controller?.splitViewItems.first { // now observe for state
observer = sideBar.observe(\.isCollapsed, options: [.new]) { [weak self] _, change in
if let value = change.newValue {
self?.sideCollapsed?.wrappedValue = value // << here !!
}
}
}

and usage like

SideViewInsideNavigationView()
.background(SplitViewAccessor(sideCollapsed: $collapsed)) // << inject finder !!

Complete findings and code is here

Collapse sidebar in SwiftUI (Xcode 12)

This worked for me -
https://developer.apple.com/forums/thread/651807

struct SwiftUIView: View {
var body: some View {
NavigationView{

}.toolbar {
ToolbarItem(placement: .navigation) {
Button(action: toggleSidebar, label: {
Image(systemName: "sidebar.left")
})
}
}
}
}

func toggleSidebar() {
NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
}

struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}

It shows in the views on iOS so you will need some conditions for macOS only.

Sidebar Menu for macOS in SwiftUI

You need to make your enum case-iterable to use it as model in ForEach, like

enum HostingBarCategories: Hashable, CaseIterable {
case Screen1
case Screen2
case Screen3
case Screen4
case Screen5

var string: String { String(describing: self) }
}

struct macOS_NavigationView: View {

@State private var selectedTab: HostingBarCategories = .Screen1

var body: some View {

NavigationView {
// SideBar Menu
List {
ForEach(HostingBarCategories.allCases, id: \.self) { screen in
NavigationLink(destination:
Text(screen.string)
.frame(maxWidth: .infinity, maxHeight: .infinity)
) {
Text("Link \(screen.string)")
}
}
}
.listStyle(SidebarListStyle())

// Primary View
Text("Select a menu...")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}


Related Topics



Leave a reply



Submit