NSToolbar в Xcode 7 с использованием раскадровок (NSWindowController - ›NSSplitViewController)

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

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

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

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

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

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

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

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

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


person gbdavid    schedule 24.06.2015    source источник


Ответы (4)


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

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

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

    @IBOutlet weak var mySplitViewItem: NSSplitViewItem!

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

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

    var mySplitViewController: MySplitViewController {return self.window? .contentViewController as! MySplitViewController}

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

    mySplitViewController. mySplitViewItem.collapsed = true

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

person gbdavid    schedule 11.07.2015

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

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

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

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

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

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

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

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

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

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

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

    @IBAction open func toggleSidebar(_ sender: Any?)
person jeff-h    schedule 11.05.2017
comment
На данный момент это лучший ответ. Спасибо! - person steve1ae; 28.08.2019

Итак, я работал с той же проблемой и не нашел решения, как вы. Я прочитал ваш пост и пытался понять, как бы реализовать ваше решение, когда мне пришло в голову использовать уведомление. Примерно через 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

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

person Dean Davids    schedule 07.02.2016
comment
При использовании этого метода следует соблюдать осторожность, если приложение имеет несколько окон (например, на основе NSDocument). Это связано с тем, что на одно уведомление ответят все открытые окна, если ваш код используется как есть. В частности, вам нужно передать какой-то идентифицирующий объект вместо nil при публикации уведомления. Наблюдая за уведомлением, вы передаете тот же объект, чтобы гарантировать, что только окно, запустившее уведомление, отреагирует на него. - person Andrew; 11.07.2016

Хотя соединение 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;
}
person Thomas Tempelmann    schedule 06.07.2021