【问题标题】:How to set custom NSSplitView with NSSplitViewController?如何使用 NSSplitViewController 设置自定义 NSSplitView?
【发布时间】:2017-09-02 17:46:57
【问题描述】:

我想在我的NSSplitViewController 中使用自定义NSSplitView

docs 说:

要提供自定义拆分视图,请在之前的任何时间设置此属性 你在继承的 viewDidLoad() 方法中调用 super;也就是说,之前 拆分视图控制器的 isViewLoaded 属性为 true。

我的NSSplitViewController 子类称为MainVC

在调用[super viewDidLoad] 之前,我尝试在-viewDidLoad 中设置我的自定义拆分视图:

- (void)viewDidLoad {
    self.splitView = [MySplitView new];
    [super viewDidLoad];
    // Rest of viewDidLoad...
}

但它没有用。我收到以下错误:

2017-09-02 10:35:43.527312-0700 Zee[6497:632581] ** * 断言 -[MainVC setSplitView:] 失败, /BuildRoot/Library/Caches/com.apple.xbs/Sources/AppKit/AppKit- 1561/控制器/NSSplitViewController.m:220

2017-09-02 10:35:43.527558-0700 Zee[6497:632581] MainVC: The -splitView 只能在视图加载前分配

我也尝试过覆盖loadView

- (void)loadView {
    self.splitView = [MySplitView new];
    [super loadView];
}

但我明白了:

2017-09-02 10:39:39.377345-0700 Zee[6575:639146] ** * -[__NSArrayM objectAtIndex:]: 空数组的索引 0 超出范围

如果我在调用[super loadView] 后执行分配,我会得到与在-viewDidLoad 中尝试时相同的错误。

如何在我的NSSplitViewController 子类中使用自定义NSSplitView

【问题讨论】:

  • 为什么你觉得需要使用 NSSplitViewController 来制作自定义拆分视图?您希望从 NSSplitView 和 NSSplitViewController 的子类中获得什么?
  • @LucasDerraugh 我想自定义分隔线的外观,子类化 NSSplitView 似乎是这样做的方法。

标签: macos cocoa appkit nssplitview nssplitviewcontroller


【解决方案1】:

此线程中接受的答案在技术上是正确的,但(可以理解)错过了 NSSplitViewController 中的一个错误,我在任何地方都没有发现该错误。这就是 2017 年 Cocoa 的发展状况,我猜……

无论如何,问题是这样的:如果你像我一样想要使用 NSSplitViewControllerNSSplitView开始只有一个视图,上面的子类化方法不会工作,你会得到来自 OP 的索引错误。有一个私有方法(用于绘制分隔线)假定两个NSSplitViewItem 始终在其中,即使NSSplitView 只有一个也可以正常工作。

我最终做的是将NSSplitViewControllerNSSplitView 子类化,并检查我是否创建了一个只有一个视图的视图并交换了一个空白的NSViewController 实例,该实例在加载阶段完成后将被删除安顿下来。我还发现直接设置splitViewController.splitViewItems = ... 效果不佳,您应该致电addSplitViewItem: 来执行此操作 - 大概有一些幕后的东西您会错过。

这个类令人讨厌地没有记录,尽管它总体上非常有用。如果你是一个任性的旅行者并且你发现了这个,希望它对你有所帮助。

【讨论】:

  • 感谢您提供的额外颜色。
【解决方案2】:

因此,索引越界问题与您的拆分视图没有任何内容有关,而不是您在初始化时做错了什么。将初始化留在 loadView 中应该没问题。只需确保您在展示之前已经用至少 2 个 NSSplitViewItem 初始化了 NSSplitViewController 子类。这是一个例子:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    MySplitViewController *vc = [MySplitViewController new];
    vc.splitViewItems = @[
        [NSSplitViewItem splitViewItemWithViewController:[MyViewController new]],
        [NSSplitViewItem splitViewItemWithViewController:[MyViewController new]]
    ];
    self.window.contentViewController = vc;
}

【讨论】:

    【解决方案3】:

    就我而言,这行得通。 (macOS 10.14、Xcode 10)

    final class SplitVC: NSSplitViewController {
        private func patch() {
            let v = NSSplitView()
            v.isVertical = true
            v.dividerStyle = .thin
            splitView = v
            splitViewItems = [
                NSSplitViewItem(viewController: NSTabViewController()),
                NSSplitViewItem(viewController: NSTabViewController()),
            ]
        }
    
        override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
            patch()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            patch()
        }
    }
    

    【讨论】:

      【解决方案4】:

      我偶然发现了我认为是这个问题的根源。它出现在splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool 的默认实现中。我认为 Apple 在该方法中错误地编制索引会导致越界错误。

      要跳过调用它们的实现,只需在您的 NSSplitViewController 子类中覆盖它:

        override func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool {
          false
        }
      

      如果您改为调用 super.shouldHideDividerAt(...),错误会再次发生:

      *** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]
      

      其他人提供的添加“虚拟” splitViewItems 的解决方案对我有用,直到我为 insertSplitViewItem 添加了覆盖并查看了我的 NSSplitViewController 子类的 .view.frame.splitViewItems,然后出现越界错误回来了,我又被卡住了。

      在感到沮丧之后,我去了 GitHub 看看我是否能走运并找到解决这个错误的人。我遇到了这个评论/代码:https://github.com/MoonfishDeFi/Composite/blob/1ccde807c690739b1739e22f02213e195265a992/cotEditor/Document%20Window/Document%20View/SplitViewController.swift#L62,它有这个解决方案但没有解释。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多