NSSplitViewController/NSSplitViewItem XIB 中的支持

NSSplitViewController/NSSplitViewItem support in XIBs

XIB 是否支持 NSSplitViewController/NSSplitViewItem?我只看到 NSSplitView

我可以只拖放 NSViewController 并将其子类化为 NSSplitViewController 吗?我如何添加 NSSplitViewItem,它通常开箱即用?

我可以很容易地在情节提要中看到对它们的支持。

拆分视图控制器不是 xib 文件对象库的一部分。使用拆分视图控制器的最简单方法是使用故事板。

如果您不愿意使用故事板,最好的选择是创建 NSSplitViewController 的子class 和 select 复选框以同时创建一个 xib 文件。

将拆分视图添加到拆分视图控制器 xib 文件。编写代码加载 xib 文件以设置拆分视图控制器。

更新

查看 NSNib class 参考以获取有关加载 xib 文件的信息。 xib 文件的文件所有者是您的 NSSplitViewController subclass。您可以使用该信息来设置拆分视图控制器。最坏的情况是你必须编写代码从 xib 文件加载拆分视图,将拆分视图控制器的拆分视图设置为你加载的拆分视图,并将拆分视图项添加到拆分视图控制器。有关详细信息,请参阅 NSSplitViewController class 参考。

是的,这是可能的。但它需要一些布线。

首先添加 NSSplitViewItem 的自定义子 class 并将 viewController 属性 公开为 IBOutlet。编译器会发出警告,所以不要忘记将 属性 标记为动态。

@interface MySplitViewItem : NSSplitViewItem
@property  IBOutlet NSViewController *viewController;
@end

@implementation MySplitViewItem
@dynamic viewController;
@end

在您的 XIB 中添加 3 个 NSViewController 对象。其中之一更改为自定义 class NSSplitViewController。重要的是要注意不要添加 NSSplitView。将 NSViewControllers 连接到它的 views。还添加 2 个对象并添加 MySplitViewItem 的自定义 class,它已暴露 viewController 并连接它。

最后一步。在加载视图之前设置 属性 splitItems of 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 设置为更喜欢 Coder + 自动布局。

为什么我更喜欢 XIB?因为我们可以创建更大的 XIB,它不会受到数据隔离的影响(可以轻松地跨 NSViewControllers 进行绑定)。

我还尝试在 viewDidLoadsetViewawakeFromNib 中添加 splitViewItems:在 NSSplitViewController 的自定义子 class 中(具有公开的 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;
}

我也想在我的不使用故事板的项目(macOS 应用程序)中添加一个 splitView 控制器。

事实证明,这很容易(在 XCode 12.4 中)。

按照建议,必须将 NSViewController 个对象添加到 xib 并将每个 view 属性 连接到相应的 'pane' (拆分视图的子视图)在界面生成器中。

然后创建NSSplitViewController的子class(不需要创建xib文件)。

将第三个 NSViewController 对象添加到 xib 并将其 class 更改为您的子对象class。然后将 both 它的 viewsplitView 属性连接到您的 splitView。如果你只是连接 splitView 属性.

它不会加载任何视图

可能不需要使用 NSSplitViewController 的子class,但它很方便,因为您可以在 viewDidLoad 中设置 splitViewItems(如下)。由于此对象(自动)是 splitView 的委托,因此您也可以根据需要覆盖委托方法。

该对象应该有通向您之前连接到 IB 窗格的 NSViewController 对象的出口。 我设置了两个名为 leftControllerrightController 的插座。 我的 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 过早,此时显然还没有分隔线,我会崩溃。更糟糕的是,它可能会传递负分频器索引 (!!)。但是您可以覆盖该方法并采取相应的行动,我对细分隔线没有问题。