swift nsoutlineview 始终打开一个根元素

swift nsoutlineview open always one root element

我使用 swift 3 和 Xcode 8 for macOS。 我使用 nsoutlineview(没有 TreeController 且处于 ViewBased 模式)

我想知道,始终可以打开一个根元素及其子元素。如果我打开另一个,实际打开的根元素应该关闭,新的将打开。

为此,我尝试使用以下代码:

@IBAction func outlineViewClickedRow(_ sender: NSOutlineView) {

for x in (0..<outlineView.numberOfRows) {               
outlineViewn.collapseItem(outlineView.item(atRow: x), collapseChildren: true)
}
outlineView.expandItem(outlineView.item(atRow: outlineView.selectedRow))

}

此 IBAction 已分配给我的 outlineView。 基本上效果不错。

但问题是:

我试过这段代码来解决第一点:

if (outlineView.isItemExpanded(outlineView.selectedRow) == true) {
  print("isExpanded")
}

但打印结果永远不会显示。 itItemExpanded 始终为 false ...

第二点同样的问题:

if (outlineView.isExpandable(outlineView.selectedRow) == true) {
  print("isExpandable")
}

始终可扩展"false"

由于您的循环会折叠所有项目,一旦完成,selectedRow 项目将始终在循环结束时折叠。如果它恰好已经展开,这将不可避免地关闭并重新打开所选项目。 (顺便说一句,您可以通过将 nil 项传递给该函数而不是使用循环来折叠所有节点)

如果您在函数的开头检查 outlineView.isItemExpanded(outlineView.selectedRow) 并且如果它已经展开则直接退出,这应该可以解决您的第一个问题。

对于第二点,您必须在某处设置项目的 "isExpandable" 属性(您没有这样做或没有向我们展示)。

我不知道您的 outlineViewClickedRow 函数链接到哪个事件,但您必须确保 outlineView.selectedItem 包含您期望的内容。根据事件的不同,行选择状态可能不会在调用 outlineViewClickedRow 之前更新(这可能会导致一些不一致的结果)。

还有一件事,您是否以某种方式禁用或隐藏了大纲视图中的原生扩展图标(三角形)?如果没有,用户将能够展开多个顶级节点而无需通过您的自动折叠逻辑。

[编辑] 我有时间测试事件行为,大纲的选择似乎在调用 IBAction 之前更新。以下函数应正确执行自动展开和折叠:

@IBAction func outlineClicked(_ sender: Any) 
{
  autoExpandAndCollapse()
}

func autoExpandAndCollapse()
{
   guard let selectedItem = outline.item(atRow:outline.selectedRow),
             outline.parent(forItem: selectedItem) == nil
   else  { return }  

   for level1Index in (0..<outline.numberOfChildren(ofItem: nil)).reversed()
   {
      if let topLevelItem = outline.child(level1Index, ofItem: nil),
         outline.isExpandable(topLevelItem)
      {
         if outline.selectedRow == outline.row(forItem: topLevelItem)
         && !outline.isItemExpanded(topLevelItem)
         { outline.expandItem(topLevelItem)   }
         else 
         { outline.collapseItem(topLevelItem) }
      }
   }
}

顺便说一句,我假设您只希望将其应用于顶级节点。如果没有,您可能可以根据您的要求调整逻辑。

[EDIT2] 进行了调整以修复单击具有相同兄弟索引的子项时关闭父项的错误,稍微简化了代码。