swift – 如何编写NSOutlineView?
我在
Xcode 8(
Swift 3)中创建NSOutlineView时遇到了麻烦.我有一个plist文件,其中包含一些我想在OutlineView中显示的信息. plist文件如下所示(示例):
Root Dictionary *(1 item) Harry Watson Dictionary *(5 items)* name String Harry Watson age Int 99 birthplace String Westminster birthdate Date 01/01/1000 hobbies Array *(2 items)* item 0 String Tennis item 1 String Piano OutlineView看起来应该非常相似,如下所示: name Harry Watson age 99 birthplace Westminster birthdate 01/01/1000 > hobbies ... (<- this should be expandable) 我已经在Google上搜索了NSOutlineView教程,但我发现的一切都是raywenderlich.com,所以我读了一下,但在我看来并不那么容易. func outlineView(_ outlineView: NSOutlineView,viewFor tableColumn: NSTableColumn?,item: Any) -> NSView? {} 我不知道该写些什么. 如果您有任何疑问,请告诉我. 在此先感谢您的亲切问候 解决方法
我发现Ray Wenderlitch的教程质量差异很大.笑话,冗长,一步一步的手握,假设你对Swift一无所知,这对我来说太令人生厌了.这是一个简短的教程,涵盖了手动和通过Cocoa Bindings填充大纲视图的基础知识.
1.手动填充大纲视图 理解NSOutlineView的关键是必须为每一行提供唯一的标识符,无论是字符串,数字还是表示行的对象. NSOutlineView将其称为项目.基于此项,您将查询数据模型以使用数据填充大纲视图. Interface Builder安装程序 我们将使用一个非常简单的NSOutlineView,只有两列:Key和Value. 选择第一列并将其标识符更改为keyColumn.然后选择第二列并将其标识符更改为valueColumn: 将单元格的标识符设置为outlineViewCell.你只需要做一次. 码 将以下内容复制并粘贴到ViewController.swift: // Data model struct Person { var name: String var age: Int var birthPlace: String var birthDate: Date var hobbies: [String] } class ViewController: NSViewController { @IBOutlet weak var outlineView: NSOutlineView! // I assume you know how load it from a plist so I will skip // that code and use a constant for simplicity let person = Person(name: "Harry Watson",age: 99,birthPlace: "Westminster",birthDate: DateComponents(calendar: .current,year: 1985,month: 1,day: 1).date!,hobbies: ["Tennis","Piano"]) let keys = ["name","age","birthPlace","birthDate","hobbies"] override func viewDidLoad() { super.viewDidLoad() outlineView.dataSource = self outlineView.delegate = self } } extension ViewController: NSOutlineViewDataSource,NSOutlineViewDelegate { // You must give each row a unique identifier,referred to as `item` by the outline view // * For top-level rows,we use the values in the `keys` array // * For the hobbies sub-rows,we label them as ("hobbies",0),("hobbies",1),... // The integer is the index in the hobbies array // // item == nil means it's the "root" row of the outline view,which is not visible func outlineView(_ outlineView: NSOutlineView,child index: Int,ofItem item: Any?) -> Any { if item == nil { return keys[index] } else if let item = item as? String,item == "hobbies" { return ("hobbies",index) } else { return 0 } } // Tell how many children each row has: // * The root row has 5 children: name,age,birthPlace,birthDate,hobbies // * The hobbies row has how ever many hobbies there are // * The other rows have no children func outlineView(_ outlineView: NSOutlineView,numberOfChildrenOfItem item: Any?) -> Int { if item == nil { return keys.count } else if let item = item as? String,item == "hobbies" { return person.hobbies.count } else { return 0 } } // Tell whether the row is expandable. The only expandable row is the Hobbies row func outlineView(_ outlineView: NSOutlineView,isItemExpandable item: Any) -> Bool { if let item = item as? String,item == "hobbies" { return true } else { return false } } // Set the text for each row func outlineView(_ outlineView: NSOutlineView,item: Any) -> NSView? { guard let columnIdentifier = tableColumn?.identifier.rawValue else { return nil } var text = "" // Recall that `item` is the row identiffier switch (columnIdentifier,item) { case ("keyColumn",let item as String): switch item { case "name": text = "Name" case "age": text = "Age" case "birthPlace": text = "Birth Place" case "birthDate": text = "Birth Date" case "hobbies": text = "Hobbies" default: break } case ("keyColumn",_): // Remember that we identified the hobby sub-rows differently if let (key,index) = item as? (String,Int),key == "hobbies" { text = person.hobbies[index] } case ("valueColumn",let item as String): switch item { case "name": text = person.name case "age": text = "(person.age)" case "birthPlace": text = person.birthPlace case "birthDate": text = "(person.birthDate)" default: break } default: text = "" } let cellIdentifier = NSUserInterfaceItemIdentifier("outlineViewCell") let cell = outlineView.makeView(withIdentifier: cellIdentifier,owner: self) as! NSTableCellView cell.textField!.stringValue = text return cell } } 结果 2.使用Cocoa绑定 填充大纲视图的另一种方法是使用Cocoa Bindings,它可以显着减少您需要编写的代码量.但是,请考虑Cocoa Bindings是一个高级主题.当它工作时,它就像魔术,但如果没有,它可能很难修复. iOS上没有Cocoa Bindings. 码 对于这个例子,让我们通过让NSOutlineView显示多人的详细信息来提高赌注. // Data Model struct Person { var name: String var age: Int var birthPlace: String var birthDate: Date var hobbies: [String] } // A wrapper object that represents a row in the Outline View // Since Cocoa Binding relies on the Objective-C runtime,we need to mark this // class with @objcMembers for dynamic dispatch @objcMembers class OutlineViewRow: NSObject { var key: String // content of the Key column var value: Any? // content of the Value column var children: [OutlineViewRow] // set to an empty array if the row has no children init(key: String,value: Any?,children: [OutlineViewRow]) { self.key = key self.value = value self.children = children } convenience init(person: Person) { let hobbies = person.hobbies.map { OutlineViewRow(key: $0,value: nil,children: []) } let children = [ OutlineViewRow(key: "Age",value: person.age,children: []),OutlineViewRow(key: "Birth Place",value: person.birthPlace,OutlineViewRow(key: "Birth Date",value: person.birthDate,OutlineViewRow(key: "Hobbies",children: hobbies) ] self.init(key: person.name,children: children) } } class ViewController: NSViewController { let people = [ Person(name: "Harry Watson","Piano"]),Person(name: "Shelock Holmes",age: 164,birthPlace: "London",year: 1854,hobbies: ["Violin","Chemistry"]) ] @objc lazy var rows = people.map { OutlineViewRow(person: $0) } override func viewDidLoad() { super.viewDidLoad() } } Interface Builder设置 在你的故事板中: >从对象库添加树控制器 | IB Object | Property | Bind To | Controller Key | Model Key Path | |-----------------|--------------------|-----------------|-----------------|-------------------| | Tree Controller | Controller Content | View Controller | | self.rows | | Outline View | Content | Tree Controller | arrangedObjects | | | Table View Cell | Value | Table Cell View | | objectValue.key | | (Key column) | | | | | | Table View Cell | Value | Table Cell View | | objectValue.value | | (Value column) | | | | | (不要将Table View Cell与Table Cell View混淆.糟糕的命名,我知道) 结果 您可以使用DateFormatter在两种方法中输出更好的日期,但这对于这个问题并不重要. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |