Hướng dẫn 1 cách sử dụng action trong UITableViewCell

UITableView được sử dụng quá thường xuyên trong tất cả các App IOS. Và việc tạo custom UITableViewCell là 1 task quá common đối với bất kỳ lập trình viên nào. Bài viết này, mình muốn trình bày 1 cách mình hay sử dụng khi tạo custom view và action trong UITableViewCell.

Tạo custom UITableViewCell

  • Để tạo custom UITableViewCell, bạn có thể kéo thả UITableViewCell vào trong UITableView ở trên UIStoryboard. Cách này thì nhanh, dễ dàng và bạn ko phải register cell vào UITableView.

  • Tuy nhiên mình thường ko làm theo cách này. Với bất kỳ UITableViewCell nào, mình sẽ tạo UITableViewCell xib riêng. Việc này tuy mất thời gian hơn nhưng nó dễ dàng reuse và maintain hơn.

  • Tạo custon UITableViewCell đi kèm với file xib. Thường mình sẽ để Reuse Indentifier của Cell trùng vời tên Class của cell đó.Ở đây sẽ là CustomTableViewCell. Và bằng cách tạo extension UITableViewCell , mình dể dàng register cell vào UITableview và dequeueReusableCell từ UITableview

// MARK: TableViewCell
extension UITableViewCell {

    static func registerNibIn(_ tableView: UITableView) {
        let identifier = String(describing: self)
        tableView.register(UINib(nibName: identifier, bundle: nil), forCellReuseIdentifier: identifier)
    }

    static func dequeueReusableCellFrom<T: UITableViewCell>(_ tableView: UITableView, indexPath: IndexPath) -> T {
        let identifier = String(describing: self)
        if let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) as? T {
            return cell
        }
        return T()
    }

}
        // register cell
        CustomTableViewCell.registerNibIn(tableView)
        
         // dequeue cell
        let cell: CustomTableViewCell = CustomTableViewCell.dequeueReusableCellFrom(tableView, indexPath: indexPath)
        

Tạo custom action

  • Function xử lý khi tap 1 button trên UITableViewCell sẽ ko đc thực hiện trên UITableViewCell, bởi vì bản chất UITableViewCell cũng chỉ là 1 view.Do đó, nó chỉ nên cung cấp action cho UIViewController nào sử dụng nó để thực hiện 1 task cụ thể.Nên hàm xử lý của action tap button sẽ phải đc thực hiện ở UIViewController.
  • Để làm đc như thế, mình làm như sau: Tạo protocol và IBAction cho button

protocol CustomTableViewCellDelegate: class {
    func cell(cell: UITableViewCell?, touchButtonAt indexPath: IndexPath?)
}

class CustomTableViewCell: UITableViewCell {

    static var height: CGFloat = 40
    private var indexPath: IndexPath?

    // delegate
    weak var delegate: CustomTableViewCellDelegate?

    // MARK: Functions
    func configView(object: AnyObject?, at indexPath: IndexPath?) {
        self.indexPath = indexPath
    }

    // MARK: IBAction
    @IBAction fileprivate  func touchButtonAddAction(sender: UIButton? ) {
        delegate?.cell(cell: self, touchButtonAt: indexPath)
    }
}
  • ở ViewController

// MARK: - UITableViewDelegate, UITableViewDataSource
extension ViewController: UITableViewDelegate, UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return CustomTableViewCell.height
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // dequeue cell
        let cell: CustomTableViewCell = CustomTableViewCell.dequeueReusableCellFrom(tableView, indexPath: indexPath)
        cell.configView(object: nil, at: indexPath)
        cell.delegate = self
        
        // return
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        tableView.deselectRow(at: indexPath, animated: true)
    }

}

// MARK: - CustomTableViewCellDelegate
extension ViewController: CustomTableViewCellDelegate {

    func cell(cell: UITableViewCell?, touchButtonAt indexPath: IndexPath?) {
        print("touch buton at indexpath \(indexPath)")
    }
}

Bằng cách đưa action của UITableViewCell ra UIViewController, thì mình có thể sử dụng custom cell này ở nhiều UIViewController