Xcode 7 中的 NSToolbar 使用故事板(NSWindowController -> NSSplitViewController)

NSToolbar in Xcode 7 using Storyboards (NSWindowController -> NSSplitViewController)

嗨,我已经看到这个问题被问过几次了,但还没有明确的答案,所以我为 xcode 7 和 swift2 创建了这个问题(这可能已经改变了一些东西)。

我使用 Xcode 7 和 Cocoa OSX 故事板 + swift2 创建了一个项目,所以我的项目从 NSWindowController 开始连接到 NSViewController(正如预期的那样!)。我向我的 window 控制器添加了一个 NSToolbar,并向工具栏添加了一个 NSButton。我将我的 NSViewController 更改为新的 NSSplitViewController 之一 links 到三个 NSViewControllers 并水平显示它们的视图 - 垂直分隔线 -(类似于您在照片应用程序或 Yosemite + 中的页面中看到的布局)。我的最终目标是我的工具栏中的按钮显示和隐藏第一个拆分。

我的理解是,我希望为了实现这一点,我应该在 NSSplitViewController 中创建一个操作,或多或少地改变自动布局约束,它们在这里的工作方式:How to do collapse and expand view in mac application?.

然后以某种方式 link 对工具栏中的 NSButton 执行此操作...它恰好在 NSWindowController 中(在层次结构中远在上层并被隔离)...

我已经解决了有关 NSToolbar 和故事板的其他问题,但未能实现我的目标:



Apple 在 WWDC15 中确实(再次)提到他们为 osx 和拥有视图控制器的拆分视图控制器创建了故事板,以便您可以将逻辑和工作转移到特定的视图控制器,所以我希望在我的拆分视图控制器中执行所有操作,因为这是需要更改的目标。

有谁知道如何从视图控制器本身实现这一点?我真的没能找到连接我的 ToolBarItem 的方法。

好吧,我几天前就提出了这个问题,但到目前为止还没有答案,所以我用我最近为解决这个问题所做的工作来回答。

创建 Xcode 项目后,我这样做了:

  • 为 NSSplitViewController
  • 创建了一个子class MySplitViewController
  • 为每个 NSSplitViewItem 添加了一个 IBOutlet。例如:

    @IBOutlet 弱变量 mySplitViewItem:NSSplitViewItem!

  • 为 NSWindow创建了一个子classWindow控制器Window控制器

  • 在链接到 NSToolbarItem(我的按钮)的 WindowController class 中添加了一个 IBAction
  • 添加了一个 属性 获取 Window 控制器的内容作为 MySplitViewController

    var mySplitViewController: MySplitViewController { return self.window?.contentViewController 为!我的拆分视图控制器 }

  • 现在我可以在我创建的操作中从 Window 控制器访问拆分视图控制器的 属性:

    我的SplitViewController。 mySplitViewItem.collapsed = 真

我创建了一些示例代码来执行此操作(但使用视图控制器并更改标签的文本 here, just in case someone wants to see a working project with this behaviour. And a blog post :)

所以,我正在处理同样的问题,但没有找到您遇到的解决方案。我阅读了您的 post 并试图弄清楚当我想到使用通知时我将如何实施您的解决方案。在大约 30 秒内,我得到了一个完美的工作解决方案:

在你的 windowController 中添加一个 IBAction 到 post 这样的通知

-(IBAction)toggleMasterViewClicked:(id)sender
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"TestNotification" object:nil];
}

将该操作连接到您的 NSToolbarItem,然后在 viewController 中将自己添加为该通知的观察者,例如

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(toggleMasterView:) name:@"TestNotification" object:nil];

在您的情况下,选择器将是 updateMyLabelText

我真的没有看到任何缺点。不需要引用其他对象,没有依赖关系。对我来说完美无缺

One person proposes to make the link using the first reponder and expecting everything to hook up at run-time (which looks a bit dodgy and not the way apple would implement it I think...).

我认为这种急救方法实际上是正确的方法。

举个例子:

在合适的视图控制器中添加类似于以下内容的内容。

@IBAction func doSomething(_ sender: AnyObject?) {
    print("Do something.")
}

这将神奇地出现在第一响应者中:

在您的故事板中,右键单击 window 控制器上方的橙色 "first responder" 图标,您应该会在很长的列表中看到 doSomething。您只需将其连接到工具栏按钮即可。

在下面的屏幕截图中,您可以看到我的 "Toggle Sidebar" 按钮已连接到我的第一响应程序中的 toggleSidebar 操作。

我什至不必编写此方法 — 它由 NSSplitViewController:

提供
    @IBAction open func toggleSidebar(_ sender: Any?)

虽然 connectiong IBActions 通过使用 First Responder 或通过向场景添加“对象”来工作,然后将其 class 更改为 window 的视图控制器 class ,这对您想指向视图控制器的 IBOutlets 和委托没有帮助。

这里有一个解决方法:

将工具栏添加到视图控制器,而不是 Window。这样,您可以轻松地在视图控制器场景中建立所有 IBOutlet 连接。我已经这样做了很多年,没有发现任何问题,即使在使用 Tabs 时也是如此。

然后,您必须在代码中分配 window 的工具栏。例如。像这样:

@interface ViewController ()
    @property (weak) IBOutlet NSToolbar *toolbar; // connect this in your storyboard to the Toolbar that you moved to the View Controller Scene
@end

- (void)viewWillAppear {
    [super viewWillAppear];
    self.view.window.toolbar = self.toolbar;
}