3

FinderとNotesには、私が再現しようとしている特異な動作があります。 NSToolbarの 'flexible space'は分割ビューの大きさを考慮しているようです。例えば、第1のボタン群は、左側でサイドバーの右側と整列する。第2のグループのアイコンは、第1の列の右側と整列する。サイドバーを広げると、ツールバーの項目も一緒に移動します。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では許可されていません。

NSToolbarItemにプライベートメソッド-setTrackedSplitView:があります。パラメータとしてNSSplitView*が必要です。分割ビューを追跡し、それを追跡する分割ビューを渡す柔軟な領域のツールバー項目で呼び出す必要があります。 Appleがメソッドを削除するのを防ぐには、メソッドを使用しようとする前に、NSToolbarItemがメソッドに応答しているかどうかを確認する必要があります。

ユーザーはツールバーをカスタマイズして並べ替えることができるので、一般的にウィンドウのツールバーのアイテムを列挙する必要があります。最初の識別子がNSToolbarFlexibleSpaceItemIdentifierの場合は、追跡する分割ビューを設定します。他のすべてのフレキシブルスペースアイテムでは、分割ビューをトラッキングするためにクリア(nilに設定)します。ツールバーデリゲートの-toolbarWillAddItem:-toolbarDidRemoveItem:メソッドで、ウィンドウが最初に設定され、再度設定されたときに、その操作を行う必要があります。別の文書化されていないデリゲートメソッド-toolbarDidReorderItem:もあります。ここで、ツールバーを更新すると便利です。

+0

これはうまくいくようです。 2つのコメント:(1) 'toolbarWillAddItem:'は、このメソッドが呼び出されたときにツールバーの項目が更新されないため、わずかに異なる動作が必要です。代わりに 'setTrackedSplitView:'はこのネットアイテムに対して直接呼び出されるべきです。 (2)残りの項目をnilに設定すると、動作が異常になり、種類が「認識できないセレクタ」というエラーが発生します。 – Eitot

+1

残りの** flexible-space **項目は 'nil'を追跡するように設定してください。私は、フードの下に、それらのアイテムのための特定のサブクラスがあると仮定します。以前にそれらのいずれかに設定してから注文を変更した可能性があるため、追跡された分割ビューをクリアする必要があります。 '-toolbarWillAddItem:'に関して、私のコードは 'dispatch_async()'をメインキューに使ってループサイクルの最後までアイテムの更新を延期します。 –

+0

'DispatchQueue.main.async()'でそれを呼び出すことは、アプリケーションが動作しているときにだけ自分のコードで動作しますが、起動時には動作しないようです。あなたはこれをどのように実装したかの例を挙げられますか? – Eitot

関連する問題