【问题标题】:Toggle Sidebar in SwiftUI NavigationView on macOS在 macOS 上的 SwiftUI NavigationView 中切换侧边栏
【发布时间】:2020-08-29 11:12:02
【问题描述】:

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

目前我将 ToolbarItem 的目标设置为 toolbarWillAddItem(_)NSToolbarDelegate 中的 AppDelegate。

我实现的 AppDelegate 内部

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

此解决方案目前正在运行。如果 SwiftUI 的实现会改变这种情况。

那么如何才能更好地做到这一点呢?

【问题讨论】:

    标签: swift macos swiftui appkit


    【解决方案1】:

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

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

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

    侧边栏查看代码:

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

    【讨论】:

      【解决方案2】:

      在 SwiftUI 2.0 中,您可以将NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil) 与这样的工具栏按钮一起使用:

      .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
      }
      

      【讨论】:

      • 如果你使用三个面板布局(侧边栏、主要、细节),它不能正常工作。 NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil) 在这方面做得更好,如果主面板或详细面板或其子视图之一是第一响应者,它也可以工作。
      【解决方案3】:

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

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

      NSApp.sendAction(#selector(NSSplitViewController.toggleSidebar(_:)), to: nil, from: nil)
      

      它将toggleSidebar 选择器发送到第一个可以对其做出反应的对象,即当前窗口中唯一的侧边栏。这种行为有更好的记录on Apple's documentation website.


      此方法是SidebarCommands() 菜单项使用的默认实现。这可以通过添加 Toggle Sidebar 菜单项找到,然后像这样获取它的选择器:

      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:)
      

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

      【讨论】:

      • 感谢分享 @diogo,尤其是展示 Apple 在后台使用的内容!
      【解决方案4】:

      我不为此使用 NavigationView。改用 HSplitView 并使用隐藏标志,如 https://stackoverflow.com/a/59228385/811010

      【讨论】:

        猜你喜欢
        • 2021-02-04
        • 1970-01-01
        • 2021-02-10
        • 2021-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-26
        • 1970-01-01
        相关资源
        最近更新 更多