在 macOS 上的 SwiftUI NavigationView 中切换侧边栏

ric*_*eck 7 macos appkit swift swiftui

我有一个带有 a 的 macOS 应用程序,NavigationView并希望在窗口的工具栏中拥有默认的 ToggleSidebar 项。

目前我将 ToolbarItem 的目标设置toolbarWillAddItem(_)NSToolbarDelegate.

在我实现的 AppDelegate 内部

@objc func toggleSidebar(_ sender: Any) {
    ((window.contentView?.subviews.first?.subviews.first?.subviews.first as? NSSplitView)?.delegate as? NSSplitViewController)?.toggleSidebar(self)
}
Run Code Online (Sandbox Code Playgroud)

此解决方案现在正在运行。如果 SwiftUI 的实现将改变这一点。

那么如何才能以更好的方式做到这一点呢?

Ire*_*Dev 9

从 macOS Big Sur beta 4 开始,您可以使用 SwiftUI 2.0 添加默认的侧边栏命令。

var body: some Scene {
    WindowGroup {
        NavigationView {
            Group {
                SidebarView()
                ContentView()
            }
        }
    }
    .commands {
        SidebarCommands()
    }
}
Run Code Online (Sandbox Code Playgroud)

此代码将添加“切换侧边栏”快捷方式:

在此处输入图片说明

侧边栏查看代码:

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


dio*_*ogo 8

虽然您可以尝试在 或 上执行#selector(NSSplitViewController.toggleSidebar(_:))keyWindow?.contentViewControllerkeyWindow?.firstResponder?在某些情况下这似乎并不能始终如一地工作。

相反,您可以使用以下命令:

NSApp.sendAction(#selector(NSSplitViewController.toggleSidebar(_:)), to: nil, from: nil)
Run Code Online (Sandbox Code Playgroud)

它将选择器发送toggleSidebar到第一个可以对其做出反应的对象,这意味着当前窗口中唯一的侧边栏。Apple 的文档网站上对此行为有更好的记录。


该方法是菜单项使用的默认实现SidebarCommands()。这是通过添加“切换侧边栏”菜单项,然后获取其选择器来找到的,如下所示:

let menu = NSApp.mainMenu!.items.first(where: { $0.title == "View" })!
let submenu = menu.submenu!.items.first(where: { $0.title == "Toggle Sidebar" })!
submenu.target // nil
submenu.action // #selector(toggleSidebar:)
Run Code Online (Sandbox Code Playgroud)

这意味着它很可能比其他方法更加一致(和支持)。


Mat*_*des 6

In SwiftUI 2.0 you can use NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil) with a toolbar button like this:

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

func toggleSidebar() {
    #if os(macOS)
    NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
    #endif
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用三个面板布局(侧边栏、主要面板、详细信息),它将无法正常工作。`NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)` 在这方面做得更好,如果主面板或详细面板或其子视图之一是第一个,也可以工作应答者。 (2认同)