Align NSToolbarItems with NSSplitView columns

后端 未结 2 647
温柔的废话
温柔的废话 2021-01-03 04:48

Finder and Notes have a peculiar behaviour that I am seeking to reproduce. The ‘flexible space’ in the NSToolbar seems to take the dimensions of the split view into account.

相关标签:
2条回答
  • 2021-01-03 05:04

    You can do this with Apple-private methods, although that's not allowed in the App Store.

    There's a private method, -setTrackedSplitView:, on NSToolbarItem. It takes an NSSplitView* as its parameter. You need to call it on the flexible-space toolbar item that you want to track a split view and pass it the split view it should track. To protect yourself against Apple removing the method, you should check if NSToolbarItem responds to the method before trying to use it.

    Since the user can customize and re-order the toolbar, you generally need to enumerate the window's toolbar's items. For the first one whose identifier is NSToolbarFlexibleSpaceItemIdentifier, you set the split view it should track. For all other flexible-space items, you clear (set to nil) the split view to track. You need to do that when the window is first set up and again in the toolbar delegate's -toolbarWillAddItem: and -toolbarDidRemoveItem: methods. There's also another undocumented delegate method, -toolbarDidReorderItem:, where I've found it useful to update the toolbar.

    0 讨论(0)
  • 2021-01-03 05:12

    When using macOS 11 or newer, you can insert NSTrackingSeparatorToolbarItem items to the toolbar, which will split up your toolbar in sections, aligned with the dividers of a NSSplitView object.

    This example adds the new separator items to a toolbar that already contains the rest of the buttons, configured in Interface Builder or in code. The target splitview concerns a standard configuration of 3 splitviews, including a sidebar panel.

    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
        }
    }
    
    0 讨论(0)
提交回复
热议问题