如何使嵌入式视图控制器成为响应者链的一部分?

时间:2017-12-20 21:32:05

标签: swift macos cocoa first-responder nsviewcontroller

我正在使用故事板开发Mac应用程序。我有一个窗口,其中显示NSViewController作为其内容,其中包含一个"容器视图控制器"嵌入NSSplitViewController

enter image description here

预期的行为是NSSplitViewController成为响应者链的一部分,这样触发第一个响应者的toggleSidebar操作的菜单项实际上会折叠{{1}的项目这标记为侧边栏。

然而,这根本不会发生,菜单项仍然是禁用的。所以我的问题是,我怎样才能让NSSplitViewController成为响应者链的一部分?

3 个答案:

答案 0 :(得分:0)

查看nextReponsder的{​​{1}}属性。此属性定义响应者链。它通常会自动设置为遵循Cocoa框架定义的响应者更改,但您可以更改它以向不同方向插入/跳过/转移链。

例如,在某些时候(不要问我什么时候),Cocoa开始在响应者链中包含窗口的控制器。为了让我的应用程序在所有版本的macOS上保持一致,我将包含这样的代码,我的窗口控制器:

NSResponder

- (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都是调整响应者链的好地方,因此它们包含或排除您想要的任何对象。

答案 1 :(得分:0)

通过将视图控制器添加到窗口委托中,最终使它可以工作(在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
    }
  }
}

我希望对其他人有所帮助。 :)

答案 2 :(得分:0)

我注意到也许其中一些解决方案已经奏效,但是我改编了https://stackoverflow.com/a/30938725/6938357中更通用的答案。

我在NSViewController上进行了扩展,以寻找补充目标。适用于NSSplitViewController以及任何带有孩子的常规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及其子类。