3

Finder和Notes具有我正在寻求重现的特有行为。 NSToolbar中的'灵活空间'似乎考虑了分割视图的尺寸。例如,第一组按钮在左侧与侧边栏的右侧对齐。第二组图标与第一列的右侧对齐。当我扩大边栏时,工具栏内容随之移动。将NSToolbarItems与NSSplitView列对齐

这有可能重现吗?

enter image description here


解决方案

与@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) 
     } 
    } 
} 

回答

2

您可以与苹果私有的方法做到这一点,虽然这在App Store中是不允许的。

有一个私人的方法,-setTrackedSplitView:NSToolbarItem。它需要一个NSSplitView*作为其参数。您需要在要跟踪分割视图的灵活空间工具栏项目上调用它,并将它传递给它应跟踪的分割视图。为了防止Apple自行删除该方法,您应该检查NSToolbarItem是否在尝试使用该方法之前对该方法做出了响应。

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

+0

太棒了,这似乎工作。两个注释:(1)'toolbarWillAddItem:'需要稍微不同的行为,因为当调用此方法时,工具栏项不会更新。应该直接在这个网络项上调用'setTrackedSplitView:'。 (2)将其余项目设置为零会导致不稳定的行为以及种类“无法识别的选择器”的错误。 – Eitot

+1

您应该只设置剩余的**灵活空间**项目以跟踪'nil'。我假设,在这个引擎盖下,这些项目有一个特定的子类。您需要清除已跟踪的分割视图,因为您可能先前已将其设置为其中一个视图,然后他们更改了顺序。关于'-toolbarWillAddItem:',我的代码会使用'dispatch_async()'将主体队列中的项目更新推迟到运行循环结束。 –

+0

在DispatchQueue.main.async()中调用它只在应用程序运行时才在我的代码中工作,但在启动时它似乎不起作用。你能举一个你如何实现这个的例子吗? – Eitot