加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

swift – 如何编写NSOutlineView?

发布时间:2020-12-14 18:55:54 所属栏目:百科 来源:网络整理
导读:我在 Xcode 8( Swift 3)中创建NSOutlineView时遇到了麻烦.我有一个plist文件,其中包含一些我想在OutlineView中显示的信息. plist文件如下所示(示例): Root Dictionary *(1 item) Harry Watson Dictionary *(5 items)* name String Harry Watson age Int 99
我在 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设置

在你的故事板中:

>从对象库添加树控制器
>选择树控制器并打开属性检查器(Cmd选项4).设置其子项的儿童关键路径.
>打开Bindings检查器(Cmd Opt 7)并为IB对象设置绑定,如下所示.

Tree Controller's Attributes

| 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混淆.糟糕的命名,我知道)

结果

NSOutline View with Cocoa Bindings

您可以使用DateFormatter在两种方法中输出更好的日期,但这对于这个问题并不重要.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读