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 和故事板的其他问题,但未能实现我的目标:
- YouTube 视频:Cocoa Programming L17 - NSToolbar 这是我发现最接近解决问题的方法,但他的方法不适用于故事板,只能创建您自己的 xib 文件。
- 在这个问题中:How to use NSToolBar in Xcode 6 and Storyboard? 一个人提议使用第一个应答器来制作 link 并期望一切都在 运行 时间挂钩(这看起来有点狡猾并且我认为这不是苹果实施它的方式......)。第二个人建议在 NSWindowController 中创建一个视图控制器变量并从那里操作它的属性......但同样,也有点狡猾。
- 我在那个问题中看到的一个最新评论似乎是解决问题的最佳方法(但仍然不如我想象的那么好)是添加一个 NSObjectController到每个场景的停靠栏,当场景加载时,将对象的值设置为另一个场景的控制器。这真的是最好的前进方式吗?如果是这样,我该如何实现?
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;
}
嗨,我已经看到这个问题被问过几次了,但还没有明确的答案,所以我为 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 和故事板的其他问题,但未能实现我的目标:
- YouTube 视频:Cocoa Programming L17 - NSToolbar 这是我发现最接近解决问题的方法,但他的方法不适用于故事板,只能创建您自己的 xib 文件。
- 在这个问题中:How to use NSToolBar in Xcode 6 and Storyboard? 一个人提议使用第一个应答器来制作 link 并期望一切都在 运行 时间挂钩(这看起来有点狡猾并且我认为这不是苹果实施它的方式......)。第二个人建议在 NSWindowController 中创建一个视图控制器变量并从那里操作它的属性......但同样,也有点狡猾。
- 我在那个问题中看到的一个最新评论似乎是解决问题的最佳方法(但仍然不如我想象的那么好)是添加一个 NSObjectController到每个场景的停靠栏,当场景加载时,将对象的值设置为另一个场景的控制器。这真的是最好的前进方式吗?如果是这样,我该如何实现?
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;
}