NSToolbar в Xcode 7, используя раскадровки (NSWindowController -> NSSplitViewController)

Привет, я уже видел этот вопрос несколько раз, но без определенного ответа, поэтому я создал его для xcode 7 и swift2 (которые в любом случае могли немного измениться).

Я создал проект с использованием плат Xcode 7 и Cocoa OSX Story + swift2, поэтому мой проект начался с NSWindowController, который подключается к NSViewController (как и ожидалось!). Я добавил NSToolbar в мой оконный контроллер и добавил NSButton на панель инструментов. Я изменил свой NSViewController, чтобы он стал одним из новых NSSplitViewController, который связывается с тремя NSViewController и отображает их виды горизонтально - с вертикальными разделителями - (аналогично макету, который вы видите в приложении для фотографий или страницах в Yosemite +). Моя конечная цель будет состоять в том, чтобы кнопка на Моей панели инструментов показывала и скрывала первое разделение.

Насколько я понимаю, и я ожидаю, что для достижения этой цели я должен создать действие в NSSplitViewController, которое более или менее изменяет ограничения автоматического макета, как они работают здесь: как свернуть и развернуть представление в Mac приложение?,

И затем каким-то образом связать это действие с NSButton, который находится на панели инструментов... который находится в NSWindowController (далеко вверх и изолирован в иерархии)...

Я уже рассмотрел другие вопросы о NSToolbar и раскадровках и не смог достичь своей цели:

  • Видео на YouTube: Cocoa Programming L17 - NSToolbar, который, как мне кажется, наиболее близок к решению проблемы, но его метод не работает для раскадровок, а только создает собственный файл xib.
  • В этом вопросе: Как использовать NSToolBar в Xcode 6 и раскадровке? Один человек предлагает создать ссылку, используя первый ответ и ожидая, что все будет подключено во время выполнения (что выглядит немного хитроумно, а не то, как Apple это реализовала бы, я думаю...). Второй человек предложил создать переменную контроллера представления в NSWindowController и манипулировать его свойствами оттуда... но опять же, немного хитроумно.

  • Один последний комментарий, который я увидел в этом вопросе и который, кажется, лучший способ решения проблемы (но все же не так хорошо, как я предполагаю, что это может быть), - это добавить NSObjectController в док каждой сцены, и когда сцена загружается, установите значения объектов для контроллера другой сцены. Это действительно лучший способ пойти дальше? Если так, как я мог достигнуть этого?

Apple снова упомянула в WWDC15, что они создали раскадровки для osx и контроллер split-view, который владеет контроллерами представления, чтобы вы могли перенести свою логику и работу на конкретный контроллер представления, так что я ожидал бы сделать все от внутри моего контроллера разделенного вида, так как это цель, которая должна измениться.

Кто-нибудь знает, как этого добиться от самого контроллера вида? Я действительно не смог найти способ подключить мой ToolBarItem к нему.

4 ответа

Решение

Хорошо, я создал этот вопрос несколько дней назад, и пока ответа нет, поэтому я отвечаю тем, что недавно сделал, чтобы преодолеть проблему.

После того, как я создал свой проект Xcode, я сделал это:

  • Создан подкласс MySplitViewController для NSSplitViewController
  • Добавлен IBOutlet для каждого NSSplitViewItem. Например:

    @IBOutlet слабый var mySplitViewItem: NSSplitViewItem!

  • Создан подкласс WindowController для NSWindowController

  • Добавлен IBAction в классе WindowController, который ссылается на NSToolbarItem (моя кнопка)
  • Добавлено свойство, которое получает содержимое контроллера окна как MySplitViewController

    var mySplitViewController: MySplitViewController {вернуть self.window?.contentViewController как! MySplitViewController }

  • Теперь я могу получить доступ к свойству контроллера разделенного вида из Window Controller в действии, которое я создал:

    mySplitViewController. mySplitViewItem.collapsed = true

Я создал некоторый пример кода, который делает это (но с использованием контроллера представления и изменением текста для метки здесь, на тот случай, если кто-то захочет увидеть работающий проект с таким поведением. И сообщение в блоге об этом тоже:)

Один человек предлагает создать ссылку, используя первый ответ и ожидая, что все будет подключено во время выполнения (что выглядит немного хитроумно, а не то, как Apple это реализовала бы, я думаю...).

Я думаю, что этот метод первого респондента на самом деле правильный путь.

В качестве примера:

Добавьте что-то похожее на следующее, в каком бы виде контроллер не имел смысла.

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

Это волшебным образом проявится в первом респонденте:

введите описание изображения здесь

В раскадровке щелкните правой кнопкой мыши оранжевый значок "первый ответчик" над контроллером окна, и вы должны увидеть doSomething в очень длинном списке. Вам просто нужно подключить это к кнопке на панели инструментов.

На следующем снимке экрана вы видите, что моя кнопка "Переключить боковую панель" подключена к toggleSidebar действие в моем первом ответчике.

введите описание изображения здесь

Мне даже не пришлось писать этот метод - он предоставляется NSSplitViewController:

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

Итак, я работал над той же проблемой и не нашел решения, которое вы испытали. Я прочитал ваш пост и пытался понять, как я смогу реализовать ваше решение, когда мне пришло в голову использовать уведомление. Примерно через 30 секунд у меня было прекрасно работающее решение:

В вашем windowController добавьте IBAction, чтобы опубликовать уведомление примерно так

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

Подключите это действие к вашему NSToolbarItemзатем в viewController добавьте себя в качестве наблюдателя для этого уведомления, как

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

В вашем случае селектор будет updateMyLabelText

Я не вижу здесь никаких недостатков. Нет необходимости ссылаться на другие объекты, нет зависимостей. У меня работает без нареканий

Хотя подключение IBActions работает либо с использованием первого ответчика, либо путем добавления «объекта» в сцену, а затем изменения его класса на класс контроллера представления окна, это не помогает с IBOutlets и делегатами, на которые вы хотите указать просмотр контроллера.

Вот как это сделать:

Добавьте панель инструментов к контроллеру представления, а не к его окну. Таким образом, вы можете легко установить все соединения IBOutlet в сцене контроллера представления. Я делал это годами и не обнаружил никаких проблем, даже при использовании вкладок.

Тогда вам нужно будет назначить панель инструментов окна в коде. Например, вот так:

      @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;
}
Другие вопросы по тегам