Поддержка NSSplitViewController/NSSplitViewItem в XIB
3 ответа
Да, это возможно. Но для этого нужна проводка.
Сначала добавьте пользовательский подкласс NSSplitViewItem
и разоблачить viewController
собственность как IBOutlet. Компилятор выдаст предупреждение, поэтому не забудьте пометить свойство как динамическое.
@interface MySplitViewItem : NSSplitViewItem
@property IBOutlet NSViewController *viewController;
@end
@implementation MySplitViewItem
@dynamic viewController;
@end
В вашей XIB добавьте 3 объекта NSViewController. Один из них меняется на пользовательский класс NSSplitViewController. Важно отметить, что не следует добавлять NSSplitView
, провод NSViewControllers
к этому views
, Также добавьте 2 объекта и добавьте пользовательский класс MySplitViewItem
который разоблачил viewController
и подключите его.
Последний шаг. Важно установить свойство splitItems
из NSSplitViewController
до того как просмотры будут загружены! В противном случае вы попадаете с макросом NSAssert.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSNib *nib = [[NSNib alloc] initWithNibNamed:@"Empty" bundle:nil];
NSMutableArray *test = [NSMutableArray new];
NSMutableArray *splitItems = [NSMutableArray new];
NSSplitViewController *controller;
[nib instantiateWithOwner:self topLevelObjects:&test];
for (id object in test) {
if ([object isKindOfClass:[NSSplitViewController class]]) {
controller = object;
}
if ([object isKindOfClass:[NSSplitViewItem class]]) {
[splitItems addObject:object];
}
}
[controller setValue:splitItems forKey:@"splitViewItems"];
[[self window] setContentViewController:controller];
}
Вот доказательство того, что все подключено правильно. Обратите внимание, что я не трогал делегат в XIB, и он подключен. Магия, я знаю.
PS: XIB должен быть установлен, чтобы предпочесть кодер + автоматическое расположение.
Почему я предпочитаю XIB? Потому что мы можем создать более крупный XIB, который не страдает от изоляции данных (легко может делать привязки через NSViewControllers).
Я также экспериментировал, чтобы добавить splitViewItems
в viewDidLoad
или же setView
или же awakeFromNib
: в пользовательском подклассе NSSplitViewController
(с открытыми свойствами NSSplitViewItem). Если кто-то найдет решение здесь, оно будет высоко оценено.
Решение, которое требует только кода:
- (NSSplitViewController *)profilesSVC
{
if (!_profilesSVC) {
NSSplitViewController *splitVC = [[NSSplitViewController alloc] init];
ProfilesViewController *profilesVC = [[ProfilesViewController alloc] initWithNibName:@"Profiles" bundle:nil];
NSSplitViewItem *leftItem = [NSSplitViewItem splitViewItemWithViewController:profilesVC];
[splitVC addSplitViewItem:leftItem];
ProfileViewController *profileVC = [[ProfileViewController alloc] initWithNibName:@"Profile" bundle:nil];
NSSplitViewItem *rightItem = [NSSplitViewItem splitViewItemWithViewController:profileVC];
[splitVC addSplitViewItem:rightItem];
_profilesSVC = splitVC;
}
return _profilesSVC;
}
Контроллер разделенного представления не является частью библиотеки объектов для файлов XIB. Самый простой способ использовать контроллеры с разделенным видом - это использовать раскадровки.
Если вы не хотите использовать раскадровки, лучше всего создать подкласс NSSplitViewController и установить флажок, чтобы также создать файл xib.
Добавьте разделенное представление в xib-файл контроллера разделенного представления. Напишите код для загрузки xib-файла для настройки контроллера разделения представления.
ОБНОВИТЬ
Посмотрите на ссылку класса NSNib для информации о загрузке файла XIB. Владельцем файла xib-файла является ваш подкласс NSSplitViewController. Возможно, вы сможете использовать эту информацию для установки контроллера разделенного представления. В худшем случае вам нужно написать код для загрузки разделенного представления из xib-файла, установить разделенное представление контроллера разделенного представления на загруженное разделенное представление и добавить элементы разделенного представления в контроллер разделенного представления. См. Ссылку на класс NSSplitViewController для получения дополнительной информации.
Я тоже хотел добавить контроллер splitView в свой проект (приложение macOS), который не использует раскадровки.
Как оказалось, это было довольно просто (в XCode 12.4).
Как было предложено, нужно добавить объекты в xib и связать каждое свойство с соответствующей «панелью» (подвид разделенного представления) в построителе интерфейса.
Затем создайте подкласс (не нужно создавать файл xib).
Добавьте третий объект в xib и измените его класс на свой подкласс. Затем проволока оба это
view
и свойства вашего splitView. Он не загружает никакого представления, если вы просто подключаете
splitView
имущество.
Использование подкласса
NSSplitViewController
может не требоваться, но это удобно, так как вы можете установить splitViewItems внутри
viewDidLoad
(ниже). Поскольку этот объект (автоматически) является делегатом splitView, вы также можете переопределить методы делегата, если хотите.
Этот объект должен иметь выходы, ведущие к
NSViewController
объекты, которые вы ранее подключили к панелям в IB. Я установил две розетки с именем
leftController
а также
rightController
. Мой
awakeFromNib
метод выглядит так (извините, я не использую swift):
- (void) viewDidLoad {
self.splitView.wantsLayer = YES; // I think this is required if you use a left sidebar with vibrancy (which I do below). Otherwise appkit complains and forces the use of CA layers anyway
NSSplitViewItem *left =[NSSplitViewItem sidebarWithViewController:leftController];
[self addSplitViewItem:left];
NSSplitViewItem *right =[NSSplitViewItem splitViewItemWithViewController:rightController];
right.minimumThickness = 420;
[self addSplitViewItem:right];
}
Вуаля!
Однако у меня возникают сбои, если я устанавливаю толстые разделители в IB при вызовах appkit.
splitView:shouldHideDividerAtIndex
слишком рано, когда делителя видимо еще нет. Хуже того, он может передать отрицательный индекс делителя (!!). Но вы можете переопределить метод и действовать соответствующим образом, и у меня нет проблем с тонкими разделителями.