[英]How to use NSOutlineView without bindings
My data looks like:我的数据看起来像:
let keysDetails : [String : Any] = [
"kAddToBag" : [
"locDict" : [
"at" : "add",
"ae" : "Add"
],
"jsonDict" : [
"at" : "add to bag",
"ae" : "ADD TO BAG"
],
"path" : "somepath"
],
"kShopTab" : [
"locDict" : [
"be_fr" : "shop",
"be_nl" : "SHOP"
],
"jsonDict" : [
"be_fr" : "shop",
"be_nl" : "SHOP"
],
"path" : "somepath2"
]
]
I want NSOutlineView to look like above picture.我希望 NSOutlineView 看起来像上图。
let keysDetails : [String : Any] = [
"kAddToBag" : [
"locDict" : [
"at" : "add",
"ae" : "Add"
],
"jsonDict" : [
"at" : "add to bag",
"ae" : "ADD TO BAG"
],
"path" : "somepath"
],
"kShopTab" : [
"locDict" : [
"be_fr" : "shop",
"be_nl" : "SHOP"
],
"jsonDict" : [
"be_fr" : "shop",
"be_nl" : "SHOP"
],
"path" : "somepath2"
]
]
Dictionary is an unordered collection and it will cause issues when you'll want to access elements via indexes, ... Let's create a custom structure which will provide data for the NSOutlineView
.字典是一个无序的集合,当你想通过索引访问元素时它会导致问题,......让我们创建一个自定义结构,它将为
NSOutlineView
提供数据。
struct Item {
let title: String // First column value
let loc: String // Second column value
let json: String // Third column value
let children: [Item] // Possible children
init(title: String, loc: String, json: String, children: [Item] = []) {
self.title = title
self.loc = loc
self.json = json
self.children = children
}
init?(title: String, content: Any) {
// Check that the content is a dictionary and that it contains
// locDict & jsonDict and both are dictionaries
guard let content = content as? [String: Any],
let loc = content["locDict"] as? [String: String],
let json = content["jsonDict"] as? [String: String] else {
return nil
}
// Check that both dictionaries contains same keys
let locKeys = loc.keys.sorted()
let jsonKeys = json.keys.sorted()
guard locKeys == jsonKeys else {
return nil
}
// Initialize top level item
self.title = title
self.loc = "locDict"
self.json = "jsonDict"
self.children = locKeys.map { key in
// We can force unwrap here because we already checked that
// both dictionaries contains same keys
Item(title: key, loc: loc[key]!, json: json[key]!)
}
}
}
This structure is an example how you can do it, but there're lot of other ways.这个结构是一个例子,你可以如何做到这一点,但还有很多其他的方法。 It really depends on what you're planning to do here.
这真的取决于你打算在这里做什么。 You can switch to an object (instead of a structure), ...
您可以切换到 object(而不是结构),...
The key point here is that the children
property is an ordered collection (array).这里的关键点是
children
属性是一个有序集合(数组)。
Add items
property (again, an ordered collection = array).添加
items
属性(再次,有序集合 = 数组)。
class ViewController: NSViewController {
private let items: [Item] = {
// Map keysDetails to an array of our Item structures
keysDetails.compactMap { (key: String, value: Any) in
Item(title: key, content: value)
}
}()
}
As the name implies, data source provides just data.顾名思义,数据源只提供数据。 We already have the
items
property, let's use it.我们已经有了
items
属性,让我们使用它。
extension ViewController: NSOutlineViewDataSource {
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
if item == nil {
// item == nil
// We're being asked for the number of top level elements (kAddToBag, ...)
return items.count
}
// Develop time (debug) - check that the item is really Item
assert(item is Item);
// item != nil
// We're being asked for the number of children of an item
return (item as! Item).children.count
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
if item == nil {
// item == nil
// We're being asked for n-th (index) top level element
return items[index]
}
// Develop time (debug) - check that the item is really Item
assert(item is Item);
// item != nil
// We're being asked for n-th (index) child of an item
return (item as! Item).children[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
// Develop time (debug) - check that the item is really Item
assert(item is Item);
// Item is expandable only if it has children
return (item as! Item).children.count > 0
}
}
Among other stuff, delegate provides cell view to display for particular item and column.除其他外,委托提供单元格视图以显示特定项目和列。
extension ViewController: NSOutlineViewDelegate {
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
// Get the column identifier and our Item
guard let columnIdentifier = tableColumn?.identifier,
let item = item as? Item else {
return nil
}
// Get a cell view identifier and an actual value we should display
let cellViewIdentifier: String
let stringValue: String
switch columnIdentifier.rawValue {
case "TitleColumn":
cellViewIdentifier = "TitleCell"
stringValue = item.title
case "LocColumn":
cellViewIdentifier = "LocCell"
stringValue = item.loc
case "JsonColumn":
cellViewIdentifier = "JsonCell"
stringValue = item.json
default:
return nil
}
// Make a view from the cell view identifier
let view = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(cellViewIdentifier), owner: self) as? NSTableCellView
// Update text field value
view?.textField?.stringValue = stringValue
return view
}
}
TitleColumn
, LocColumn
, JsonColumn
TitleColumn
、 LocColumn
、 JsonColumn
TitleCell
, LocCell
, JsonCell
TitleCell
、 LocCell
、 JsonCell
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.