6

Finder 和 Notes 具有我正在寻求重现的特殊行为。NSToolbar 中的“灵活空间”似乎考虑了拆分视图的尺寸。例如,第一组按钮在侧边栏的左侧与右侧对齐。第二组图标与第一列的右侧对齐。当我加宽侧边栏时,工具栏项目会随之移动。

有可能重现这个吗?

在此处输入图像描述


解决方案

使用@KenThomases 提供的解决方案,我实现了如下:

final class MainWindowController: NSWindowController {
    override func windowDidLoad() {
        super.windowDidLoad()
        window?.toolbar?.delegate = self
        // Make sure that tracking is enabled when the toolbar is completed
        DispatchQueue.main.async {
            self.trackSplitViewForFirstFlexibleToolbarItem()
        }
    }
}

extension MainWindowController: NSToolbarDelegate {
    func toolbarWillAddItem(_ notification: Notification) {
        // Make sure that tracking is evaluated only after the item was added
        DispatchQueue.main.async {
            self.trackSplitViewForFirstFlexibleToolbarItem()
        }
    }

    func toolbarDidRemoveItem(_ notification: Notification) {
        trackSplitViewForFirstFlexibleToolbarItem()
    }

    /// - Warning: This is a private Apple method and may break in the future.
    func toolbarDidReorderItem(_ notification: Notification) {
        trackSplitViewForFirstFlexibleToolbarItem()
    }

    /// - Warning: This method uses private Apple methods that may break in the future.
    fileprivate func trackSplitViewForFirstFlexibleToolbarItem() {
        guard var toolbarItems = self.window?.toolbar?.items, let splitView = (contentViewController as? NSSplitViewController)?.splitView else {
            return
        }

        // Add tracking to the first flexible space and remove it from the group
        if let firstFlexibleToolbarItem = toolbarItems.first, firstFlexibleToolbarItem.itemIdentifier == NSToolbarFlexibleSpaceItemIdentifier {
            _ = firstFlexibleToolbarItem.perform(Selector(("setTrackedSplitView:")), with: splitView)
            toolbarItems.removeFirst()
        }

        // Remove tracking from other flexible spaces
        for flexibleToolbarItem in toolbarItems.filter({ $0.itemIdentifier == NSToolbarFlexibleSpaceItemIdentifier }) {
            _ = flexibleToolbarItem.perform(Selector(("setTrackedSplitView:")), with: nil)
        }
    }
}
4

2 回答 2

5

使用 macOS 11 或更高版本时,您可以将NSTrackingSeparatorToolbarItem项目插入工具栏,这会将工具栏分成多个部分,与NSSplitView对象的分隔线对齐。

此示例将新的分隔项添加到已包含其余按钮的工具栏,这些按钮在 Interface Builder 或代码中进行配置。目标拆分视图涉及 3 个拆分视图的标准配置,包括一个侧边栏面板。

class WindowController: NSWindowController, NSToolbarDelegate {

    let mainPanelSeparatorIdentifier = NSToolbarItem.Identifier(rawValue: "MainPanel")

    override func windowDidLoad() {
        super.windowDidLoad()

        self.window?.toolbar?.delegate = self
    
        // Calling the inserts async gives more time to bind with the split viewer, and prevents crashes
        DispatchQueue.main.async {

            // The .sidebarTrackingSeparator is a built-in tracking separator which always aligns with the sidebar splitview
            self.window?.toolbar?.insertItem(withItemIdentifier: .sidebarTrackingSeparator, at: 0)
        
            // Example of a custom mainPanelSeparatorIdentifier
            // Index at '3' means that there are 3 toolbar items at the left side
            // of this separator, including the first tracking separator
            self.window?.toolbar?.insertItem(withItemIdentifier: mainPanelSeparatorIdentifier at: 3)
        }
    }

    func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
    
        if let splitView = (self.contentViewController as? NSSplitViewController)?.splitView {
        
            // You must implement this for custom separator identifiers, to connect the separator with a split view divider
            if itemIdentifier == mainPanelSeparatorIdentifier {
                return NSTrackingSeparatorToolbarItem(identifier: itemIdentifier, splitView: splitView, dividerIndex: 1)
            }
        }
        return nil
    }
}

如果您想添加一个额外的分隔符,例如为 Inspector 面板,只需在工具栏中插入一个额外的工具栏项标识符,然后在委托函数NSTrackingSeparatorToolbarItem中为另一个分隔符分配一个额外的标识符。itemForItemIdentifier

于 2020-07-29T09:14:26.693 回答
2

您可以使用 Apple 私有方法执行此操作,尽管 App Store 不允许这样做。

有一个私有方法-setTrackedSplitView:, on NSToolbarItem。它接受一个NSSplitView*作为它的参数。您需要在要跟踪拆分视图的灵活空间工具栏项上调用它,并将它应该跟踪的拆分视图传递给它。为了保护自己免受 Apple 删除该方法的影响,您应该NSToolbarItem在尝试使用该方法之前检查是否响应该方法。

由于用户可以自定义和重新排序工具栏,您通常需要枚举窗口工具栏的项目。对于标识符为 的第一个NSToolbarFlexibleSpaceItemIdentifier,您设置它应该跟踪的拆分视图。对于所有其他灵活空间项目,您清除(设置为nil)要跟踪的拆分视图。您需要在第一次设置窗口并再次在工具栏委托-toolbarWillAddItem:-toolbarDidRemoveItem:方法中执行此操作。还有另一个未记录的委托方法,-toolbarDidReorderItem:我发现更新工具栏很有用。

于 2016-12-29T03:20:59.053 回答