【问题标题】:NSToolbar in Xcode 7 using Storyboards (NSWindowController -> NSSplitViewController)Xcode 7 中的 NSToolbar 使用 Storyboards (NSWindowController -> NSSplitViewController)
【发布时间】:2021-07-06 22:29:59
【问题描述】:

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

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

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

然后以某种方式将此操作链接到工具栏中的 NSButton... 它恰好位于 NSWindowController 中(在层次结构中很远且隔离)...

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

  • YouTube 视频:Cocoa Programming L17 - NSToolbar 这是我找到的最接近解决问题的方法,但他的方法不适用于情节提要,只能创建您自己的 xib 文件。
  • 在这个问题中:How to use NSToolBar in Xcode 6 and Storyboard? 一个人建议使用第一个响应器建立链接,并期望一切都在运行时连接(这看起来有点狡猾,而不是我认为苹果会实现它的方式...... )。第二个人建议在 NSWindowController 中创建一个视图控制器变量并从那里操作它的属性......但同样,也有点狡猾。

  • 我在那个问题中看到的一个最新评论 似乎是解决问题的最佳方法(但仍然不如我想的那么好)是将 NSObjectController 添加到每个场景,当场景加载时,将对象的值设置到另一个场景的控制器。这真的是最好的前进方式吗?如果是这样,我怎么能做到这一点?

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

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

【问题讨论】:

    标签: macos swift xcode7 nstoolbar nssplitviewcontroller


    【解决方案1】:

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

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

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

      @IBOutlet 弱变量 mySplitViewItem: NSSplitViewItem!

    • 为 NSWindowController 创建了一个子类 WindowController

    • 在 WindowController 类中添加了一个链接到 NSToolbarItem(我的按钮)的 IBAction
    • 添加了一个属性,将窗口控制器的内容作为 MySplitViewController

      var mySplitViewController: MySplitViewController { 返回 self.window?.contentViewController 作为! MySplitViewController }

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

      mySplitViewController。 mySplitViewItem.collapsed = true

    我创建了一些示例代码来执行此操作(但使用视图控制器并更改标签 here 的文本,以防万一有人希望看到具有这种行为的工作项目。还有一个 blog post 关于它:)

    【讨论】:

      【解决方案2】:

      有人建议使用第一个响应器建立链接,并期望所有东西在运行时都连接起来(这看起来有点狡猾,我认为这不是苹果的实现方式......)。

      我认为这种第一响应者方法其实是正确的方法。

      举个例子:

      添加类似于以下内容的内容,无论哪个视图控制器都有意义。

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

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

      在您的故事板中,右键单击窗口控制器上方的橙色“第一响应者”图标,您应该会在很长的列表中看到 doSomething。您只需要将它连接到您的工具栏按钮即可。

      在以下屏幕截图中,您可以看到我的“切换侧边栏”按钮已连接到我的第一响应者中的 toggleSidebar 操作。

      我什至不用写这个方法——它由NSSplitViewController提供:

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

      【讨论】:

      • 这是迄今为止最好的答案。谢谢!
      【解决方案3】:

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

      在你的 windowController 中添加一个 IBAction 来发布这样的通知

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

      将该操作连接到您的 NSToolbarItem,然后在 viewController 中添加 self 作为该通知的观察者,如下所示

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

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

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

      【讨论】:

      • 使用此方法时,如果应用程序有多个窗口(例如基于 NSDocument),则需要注意。这是因为如果您的代码按原样使用,所有打开的窗口都会响应单个通知。具体来说,您需要在发布通知时传递一些标识对象而不是 nil。在观察通知时,您传递相同的对象以确保只有触发通知的窗口才会响应它。
      【解决方案4】:

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

      这里有一个解决方法:

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

      然后,您必须在代码中指定窗口的工具栏。例如。像这样:

      @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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-21
        • 2013-07-31
        • 1970-01-01
        • 1970-01-01
        • 2014-08-04
        • 2012-01-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多