2017-07-28 66 views
1

我在Xcode 8(Swift 3)中创建一个NSOutlineView时遇到了麻烦。我有一个plist文件,其中包含一些我想在OutlineView中呈现的信息。 plist文件看起来如下(举例):如何编程一个NSOutlineView?

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) 

我已经搜索在谷歌NSOutlineView教程,但一切我发现了raywenderlich。所以我读了一下,但在我看来这并不容易。 所以我想知道你是否能帮助我,确切上面的例子,给我一些代码示例,尤其是关于此功能:

func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {} 

。我不知道该写什么。

如果您有任何问题,请告诉我。

在此先感谢和亲切的问候

+0

在我看来,他们的例子很简单。 –

+0

@ElTomato嘿,谢谢你的评论 - 你是什么意思?这是我自己的榜样!?!如果你认为这很容易,你能帮助我吗?我很感谢你的帮助。 –

+0

你尝试了什么? – Willeke

回答

4

我找到雷Wenderlitch的教程质量差异很大。这些笑话,冗长的句子,假设你对Swift一无所知的一步一步的手持操作对我来说太过恶心。这是一个简洁的教程,涵盖了大纲视图的基础知识。


了解NSOutlineView的关键是,你必须给每个行的唯一标识符,是一个字符串或代表该行的对象。 NSOutlineView称之为item。基于此item,您将查询您的数据模型以用数据填充大纲视图。

Interface Builder中设置

我们将使用一个只有两列很简单NSOutlineView:关键和价值。

选择第一列并将其标识符更改为keyColumn。然后选择第二柱,并改变其标识符以valueColumn

Set the identifier for the Key column. Repeat for the Value column

设置该小区的标识符outlineViewCell。你只需要做一次。 Set the identifier for the cell

代码

复制并粘贴以下到您的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, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { 
     guard let columnIdentifier = tableColumn?.identifier 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 cell = outlineView.make(withIdentifier: "outlineViewCell", owner: self) as! NSTableCellView 
     cell.textField!.stringValue = text 

     return cell 
    } 
} 

结果

NSOutlineView

可以使用DateFormatter为更好的日期输出,但是这不是必需的对于这个问题。

+0

嘿,非常感谢!我会投入一些时间来了解所有这些,感谢您的帮助! ;-) –

0

一个清晰的例子,完美的作为一个开始使用NSOutlineView。
当我使用后来的Swift版本时,我必须将switch (columnIdentifier, item)更改为switch (columnIdentifier.rawValue, item)
Interface Builder也做了正确的调整设置let cell = outlineView.make(withIdentifier: "outlineViewCell", owner: self) as! NSTableCellView

let cell = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "outlineViewCell"), owner: self) as! NSTableCellView