2017-07-28 20 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