gpt4 book ai didi

macos - 如何将工具栏(或其项目)与分割 View Controller 子项的前缘对齐?

转载 作者:行者123 更新时间:2023-12-03 16:53:40 24 4
gpt4 key购买 nike

在 iOS 中,可以将工具栏添加到任何 View 。然而,在 macOS 中,似乎只能将工具栏添加到窗口。

我正在开发一个带有工具栏的 Split View Controller 的应用程序,但工具栏的项目仅对右 View Controller 的上下文有意义

例如假设我有某种类型的文本编辑器,其中左侧 Pane 显示所有文档(就像在 Notes 应用程序中一样),右侧 Pane 显示可以编辑的实际文本。格式化按钮仅影响右 Pane 中的文本。因此,将工具栏放置在右侧 Pane 中而不是将其拉伸(stretch)到窗口的整个宽度似乎非常直观。

Example window with split view controller

有什么方法可以实现这一目标吗?
(或者是否有一个很好的用户体验理由说明为什么这是一个不好的做法?)

我注意到苹果如何在 Notes 应用程序中的用户体验方面解决了这个问题:他们仍然使用全角工具栏,但将仅与右 Pane 相关的按钮项目与该 Pane 的前缘对齐。

Notes App Screenshot

因此,如果无法将工具栏放置在 View Controller 中,如何将工具栏项与右 View Controller 的前缘对齐,如上面的屏幕截图所示?

<小时/>

编辑:

根据 TimTwoToes' 的回答和评论中 Willeke 链接的帖子,似乎可以使用自动布局来约束具有分割 View 的工具栏项目 child View 。如果有固定的工具栏布局,则该解决方案将起作用。但是,Apple 鼓励(有充分的理由)让用户自定义应用程序的工具栏。

因此,我无法向工具栏中的固定项目添加约束。相反,一个可行的解决方案似乎是使用领先的灵活空间并相应地调整其大小。

最佳答案

初始注释

事实证明这很棘手,因为有很多事情需要考虑:

  • 自动布局似乎无法与工具栏项目一起正常工作。 (我读过一些帖子,提到苹果已将其归类为错误。)

  • 通常,用户可以自定义应用程序的工具栏(添加和删除项目)。我们不应该剥夺用户的选择权。

因此,简单地使用分割 View 或布局指南来限制特定的工具栏项目不是一个选项(因为该项目可能位于与预期不同的位置或根本不存在)。

经过几个小时的“黑客攻击”,我终于找到了一种可靠的方法来实现所需的行为,而不使用任何内部/未记录的方法。它的外观如下:

Example animation of resizing flexible view

<小时/>

如何

  1. 而不是标准 NSToolbarFlexibleSpaceItem创建 NSToolbarItem具有自定义 View 。这将作为您灵活的、可调整大小的空间。您可以在代码或 Interface Builder 中执行此操作:

    Toolbar customization in Interface Builder

  2. 为您的工具栏和灵活空间创建导出/属性(在相应的 NSWindowController 内):

    @IBOutlet weak var toolbar: NSToolbar!
    @IBOutlet weak var tabSpace: NSToolbarItem!
  3. 在同一窗口 Controller 内创建一个调整空间宽度的方法:

    private func adjustTabSpaceWidth() {
    for item in toolbar.items {
    if item == tabSpace {
    guard
    let origin = item.view?.frame.origin,
    let originInWindowCoordinates = item.view?.convert(origin, to: nil),
    let leftPane = splitViewController?.splitViewItems.first?.viewController.view
    else {
    return
    }

    let leftPaneWidth = leftPane.frame.size.width
    let tabWidth = max(leftPaneWidth - originInWindowCoordinates.x, MainWindowController.minTabSpaceWidth)

    item.set(width: tabWidth)
    }
    }

    }

  4. 定义 set(width:) NSToolbarItem 扩展中的方法如下:

    private extension NSToolbarItem {

    func set(width: CGFloat) {
    minSize = .init(width: width, height: minSize.height)
    maxSize = .init(width: width, height: maxSize.height)
    }

    }
  5. 使您的窗口 Controller 符合 NSSplitViewDelegate并将其分配给您的分割 View 的 delegate属性。1 实现以下 NSSplitViewDelegate窗口 Controller 中的协议(protocol)方法:

    override func splitViewDidResizeSubviews(_ notification: Notification) {
    adjustTabSpaceWidth()
    }

这将产生所需的调整大小行为。 (用户仍然可以完全删除空格或重新定位它,但他始终可以将其添加回前面。)

<小时/>

1 注意:

如果您使用 NSSplitViewController ,系统会自动将该 Controller 分配给其分割 View 的 delegate属性(property),你无法改变它。因此,您需要子类 NSSplitViewController ,覆盖其 splitViewDidResizeSubviews()方法并从那里通知窗口 Controller 。您可以使用以下代码来实现:

protocol SplitViewControllerDelegate: class {
func splitViewControllerDidResize(_ splitViewController: SplitViewController)
}

class SplitViewController: NSSplitViewController {

weak var delegate: SplitViewControllerDelegate?

override func splitViewDidResizeSubviews(_ notification: Notification) {
delegate?.splitViewControllerDidResize(self)
}

}

不要忘记将您的窗口 Controller 指定为分割 View Controller 的委托(delegate):

override func windowDidLoad() {
super.windowDidLoad()
splitViewController?.delegate = self
}

并实现相应的委托(delegate)方法:

extension MainWindowController: SplitViewControllerDelegate {

func splitViewControllerDidResize(_ splitViewController: SplitViewController) {
adjustTabSpaceWidth()
}

}

关于macos - 如何将工具栏(或其项目)与分割 View Controller 子项的前缘对齐?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54944038/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com