Hướng dẫn lập trình ứng dụng cho MacOS: Part 3 - Tùy biến trên NSTableView

Ở phần 2 (here), Chúng ta đã biết được làm thế nào để hiển thị thông tin dạng danh sách, cách hiển thị và đỗ dữ liệu vào TableView như thế nào. Trong phần này, chúng ta sẽ tìm hiểu thêm về tương tác trên NSTableView.

Chúng ta sẽ tiếp tục sử dụng project của Part 2 để tiếp tục thực hành tiếp, nếu bạn chưa làm hoặc đã thất lạc thì có thể tải lại đây (Link).

1. Lựa chọn của người dùng:

Khi người dùng chọn một hay nhiều file, ứng dụng sẽ cập nhập thông tin ở thanh dưới, hiển thị có bao nhiều file trong folder hay bao nhiêu file được người dùng lựa chọn. Để phục vụ việc xác nhận những selection (lựa chọn) của người dùng trên Table View, chúng cần thêm hàm: tableViewSelectionDidChange(😃 trong delegate của TableView. Hàm này sẽ được gọi khi TableView thay đổi selection. Thêm đoạn code này trong ViewController implementation:

func updateStatus() {
  let text: String
  // 1
  let itemsSelected = tableView.selectedRowIndexes.count
  // 2
  if (directoryItems == nil) {
    text = "No Items"
  }
  else if(itemsSelected == 0) {
    text = "\(directoryItems!.count) items"
  }
  else {
    text = "\(itemsSelected) of \(directoryItems!.count) selected"
  }
  // 3
  statusLabel.stringValue = text
}

Hàm này update lại label trang thái đựa trên lựa chọn của người dùng:

  1. Tableview có property selectedRowIndexes chứa những index của các dòng đã được chọn. Muốn biết có bao nhiều dòng được lựa chọn, chỉ cần lấy count của nó.
  2. Dựa theo số lượng item được chọn, đưa ra đoạn text có bao nhiều file được chọn
  3. Cập nhập lại trên statusLabel.

Bây giờ, chúng ta chỉ có việc gọi hàm updateStatus khi người dùng thay đổi selection. Thêm đoạn code nào vào trong extension tableView Delegate:

func tableViewSelectionDidChange(_ notification: Notification) {
  updateStatus()
}

Khi người dùng lựa chọn thay đổi, hàm này sẽ được gọi bởi TableView, và nó sẽ Update thông tin ở thanh Status Bar. Kết quả như hình:

2. Xử lý Doule-Click

Khi người dùng sử dụng máy tính xài hệ điều hành Win hay Mac thì việc nhấn đúp chuột trái (nhấn kép) có nghĩa người dùng đang muốn thực hiện một tác vụ với đối tượng đó, và việc của cúng ta là xứ lý nó trên ứng dụng của mình. Ở ứng dụng quản lý file, chúng ta thường nhấp đúp chuột vào file để mở folder hoặc mở file đó bằng ứng dụng mặc định của file đó. TableView không thông báo Double-click thông qua Delegate, mà thay vào chúng ta truyền action vào TableView. Thêm đoạn code vào trong hàm viewDidLoad() trong file ViewController:

tableView.target = self
tableView.doubleAction = #selector(tableViewDoubleClick(_:))

Và điền thêm hàm tableViewDoubleClick(_😃 vào:

func tableViewDoubleClick(_ sender:AnyObject) {
 
  // 1
  guard tableView.selectedRow >= 0,     
      let item = directoryItems?[tableView.selectedRow] else {
    return
  }
  if item.isFolder {
    // 2
    self.representedObject = item.url as Any
  }
  else {
    // 3
    NSWorkspace.shared().open(item.url as URL)
  }
}

Code đã được break theo từng bước:

  1. Đảm bảo việc số dòng được lựa chọn không âm, và index nằm trong danh sách file mà directoryItems quản lý, đồng thời lấy đối tượng item đó ra từ directoryItems.
  2. Nếu item đó là folder, thì lại để lại biến representedObject là url của item đó. Sau đó, tableview sẽ tự động reload lại nội dung theo url được đặt
  3. Nếu là một file, thì mở nó bằng ứng dụng mặc định, sử dụng NSWorkspace gọi hàm openURL()

3. Sắp xếp dữ liệu:

Ai cũng muốn file được sắp xếp gọn gàng, phân vùng rõ ràng. Ở phần này, chúng ta sẽ sắp xếp lại dữ liệu trong tableView dựa theo lựa chọn người dùng. Thêm đoạn code nào vào trong viewDidLoad() để tạo chú thích cho việc sắp xếp.

// 1
let descriptorName = NSSortDescriptor(key: Directory.FileOrder.Name.rawValue, ascending: true)
let descriptorDate = NSSortDescriptor(key: Directory.FileOrder.Date.rawValue, ascending: true)
let descriptorSize = NSSortDescriptor(key: Directory.FileOrder.Size.rawValue, ascending: true)
 
// 2
tableView.tableColumns[0].sortDescriptorPrototype = descriptorName
tableView.tableColumns[1].sortDescriptorPrototype = descriptorDate
tableView.tableColumns[2].sortDescriptorPrototype = descriptorSize

Đoạn code này:

  1. Tạo chú thích sắp xếp cho từng cột, với mỗi cột đều có key của riêng nó (Name, Date và Size).
  2. Add các chú thích đã vào đó vào trong từng cột của TableView. Khi người dùng click vào tên Header của từng cột, TableView sẽ gọi hàm tableView(:sortDescriptorsDidChange:) để thông báo người dùng đã lựa chọn sắp xếp theo chú thích nào? Thêm ngay đoạn code này vào trong data source của TableView
func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
  // 1
  guard let sortDescriptor = tableView.sortDescriptors.first else {
    return
  }
  if let order = Directory.FileOrder(rawValue: sortDescriptor.key!) {
    // 2
    sortOrder = order
    sortAscending = sortDescriptor.ascending
    reloadFileList()
  }
}

Build và chạy thử. Bằng việc click vào title của từng cột để sắp xếp lại danh sách file trong TableView.

Kết luận:

Bạn có thể tải project sẳn tại đây: Here Chúng ta đã đi vòng qua một lượt để có thể sử dụng và hiển thị TableView, hiển thị danh sách, tùy biến, lắng nghe các sự kiện. Bạn có thể tìm hiểu kĩ hơn ở các tài liệu dưới đây: Apple’s Table View Programming Guide for Mac. WWDC 2016 – Session 239 Video – Crafting Modern Cocoa Apps for a fast course in how to build a cutting edge table view.