簡體   English   中英

如何使嵌入式視圖控制器成為響應者鏈的一部分?

[英]How to make embedded view controller part of the responder chain?

我正在使用故事板開發 Mac 應用程序。 我有一個窗口,它顯示一個NSViewController作為其內容,其中包含一個嵌入NSSplitViewController的“容器視圖控制器”。

在此處輸入圖片說明

預期的行為是NSSplitViewController成為響應者鏈的一部分,這樣在第一響應者上觸發toggleSidebar操作的菜單項實際上會折疊標記為側邊欄的NSSplitViewController項。

但是,這根本不會發生並且菜單項保持禁用狀態。 所以我的問題是,如何讓NSSplitViewController成為響應者鏈的一部分?

我注意到其中一些解決方案可能已經奏效,但我改編了來自https://stackoverflow.com/a/30938725/6938357的更通用的答案。

我在NSViewController上做了一個擴展來尋找補充目標。 適用於NSSplitViewController以及任何帶有 child(ren) 的通用NSViewController

extension NSViewController {

    open override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? {
        if let target = super.supplementalTarget(forAction: action, sender: sender) {
            return target
        }

        for child in children {
            var target = NSApp.target(forAction: action, to: child, from: sender) as? NSResponder

            if target?.responds(to: action) == false {
                target = child.supplementalTarget(forAction: action, sender: sender) as? NSResponder
            }

            if target?.responds(to: action) == true {
                return target
            }
        }

        return nil
    }
}

如果您只想在單個視圖控制器上搜索它,請將這個實現放在那里。 此擴展適用於所有NSViewController及其子類。

退房nextReponsder財產NSResponder 此屬性定義響應者鏈。 它通常會自動設置為遵循 Cocoa 框架定義的響應者更改,但您可以更改它以在不同方向插入/跳過/轉移鏈。

例如,在某些時候(不要問我什么時候),Cocoa 開始在響應者鏈中包含窗口的控制器。 為了讓我的應用程序在所有版本的 macOS 上一致運行,我將在我的窗口控制器中包含這樣的代碼:

- (void)windowDidLoad
{
    // Sent when the controller's window has been loaded from the nib
    [super windowDidLoad];
    NSWindow* window = self.window;

    // Make sure this window controller is in the responder chain
    NSResponder* nextResponder = window.nextResponder;  // get our window's next responder
    if (nextResponder!=self)
        {
        // running earlier OS X that does not include the window controller in the chain: patch us in
        self.nextResponder = nextResponder;
        window.nextResponder = self;
        }

-windowDidLoad-viewDidLoad-awakeFromNib都是調整響應鏈的好地方,以便它們包括或排除您想要的任何對象。

我最終通過將我的視圖控制器添加到窗口委托來使其工作(在 Swift 4 中)。 之后,我的視圖控制器成為響應者鏈的一部分(這使得應用程序菜單項在我的視圖控制器中工作)。

//Step 1: Add NSWindowDelegate to the controller
class MyViewController: NSViewController, NSWindowDelegate{
  override func viewDidLoad() {
    super.viewDidLoad()

    //Step 2: Add the view controller to the window delegate
    if let window = NSApp.windows.first{
      window.delegate = self
    }
  }
}

我希望能幫助別人。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM