Làm gọn khai báo table view
Bài đăng này đã không được cập nhật trong 7 năm
Tản mạn
Table view là view được sử dụng nhiều nhất trong lập trình iOS. Khi chúng ta sử dụng table view và dùng custom cell, chúng ta sẽ có hai quá trình khai báo chính.
- Khai báo cell custom với table
- Lấy cell được khởi tạo từ hệ thống đế hiển thị Hai quá trình này lập đi lập lại và code của nó khá nhàm chán. Thông thường chúng ta sẽ làm như sau: Khai báo cell cho table view
tableView.register(<#T##nib: UINib?##UINib?#>, forCellReuseIdentifier: <#T##String#>)
Reuse cell
tableView.dequeueReusableCell(withIdentifier: <#T##String#>, for: <#T##IndexPath#>)
Hôm nay mình sẽ dùng protocol để đỡ phải code lập đi lập lại hai khai báo trên.
Action
Tạo demo hiển thị list contact
Chúng ta sẽ tạo demo single page đơn giản với một table view chính. Đầu tiên, mình sẽ tạo class Contact với 2 dữ liệu cơ bản gồm name và image.
import UIKit
final class Contact: NSObject {
var name: String!
var avatar: UIImage?
init(name: String, avatar: UIImage?) {
self.name = name
self.avatar = avatar
}
}
Tiêp theo, mình sẽ tạo mock data cho contact với Mock protocol
protocol Mock {
static func Mock() -> Self
}
extension Contact : Mock {
static func Mock() -> Contact {
let arrayNames = ["Duong", "An", "Tuan", "Dat"]
let arrayImages = [#imageLiteral(resourceName: "chandung"), #imageLiteral(resourceName: "chandung1"), #imageLiteral(resourceName: "chandung2"), #imageLiteral(resourceName: "chandung3")]
let randomNameNum = Int.randomInt(max: 3)
let randomImageNum = Int.randomInt(max: 3)
let contact = Contact(name: arrayNames[randomNameNum], avatar: arrayImages[randomImageNum])
return contact
}
}
extension Int {
static func randomInt(max: Int) -> Int {
return Int(arc4random_uniform(UInt32(max)))
}
}
Tiếp theo là contact cell
class ContactTableViewCell: UITableViewCell, BaseCellProtocol {
@IBOutlet weak var contactAvatarImageView: UIImageView!
@IBOutlet weak var contactNameLabel: UILabel!
var contact: Contact! {
didSet {
if let avatar = contact.avatar {
self.contactAvatarImageView.image = avatar
}
self.contactNameLabel.text = contact.name
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
Cuối cùng là ContactTableView
class ContactsTableViewController: UITableViewController {
var contactList = [Contact]()
override func viewDidLoad() {
super.viewDidLoad()
//Mock data
for _ in 1...10 {
self.contactList.append(Contact.Mock())
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contactList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.dequeueReusableCell(withIdentifier: "ContactTableViewCell", for: indexPath)
cell.contact = contactList[indexPath.row]
return cell
}
}
Enhance việc khai báo Cell và sử dụng cell trong table
Chúng ta sẽ tạo protocol BaseTableCell với 2 hành vi chính, getNibName và getNib. Có thể dùng được cho cả collection view cell.
/**
cell protocol for uicollectionview, uitableview
*/
protocol BaseCellProtocol {
static func getNibName() -> String // return nibname of cell
static func getNib() -> UINib // return nib of cell
}
/**
default implement for cell
*/
extension BaseCellProtocol where Self : UIView {
static func getNibName() -> String {
return String(describing: self)
}
static func getNib() -> UINib {
let mainBundle = Bundle.main
return UINib.init(nibName: self.getNibName(), bundle: mainBundle)
}
}
việc tạo extension sẽ giúp chúng ta đỡ công đi thao tác nhiều với String. Bạn chỉ cần đặt reuseIdentifier giống với tên cell là được.
Vậy là xong phần về TableViewCell, giờ chúng ta sẽ tiếp tục với TableView. Tiếp tục sử dụng protocol cho tableView. Chúng ta sẽ viết protocol cho 2 quá trình register cell vè deuse cell.
extension UITableView {
func on_register< T : BaseCellProtocol>(type: T.Type) {
self.register(T.getNib(), forCellReuseIdentifier: T.getNibName())
}
func on_dequeue< T : BaseCellProtocol>(idxPath : IndexPath) -> T {
guard let cell = self.dequeueReusableCell(withIdentifier: T.getNibName(), for: idxPath) as? T else {
fatalError("couldnt dequeue cell with identifier \(T.getNibName())")
}
return cell
}
}
Vậy giờ khi register cell cho tableView ta chỉ cần khai báo
tableView.on_register(type: ContactTableViewCell.self)
Và khi dequeue cell cũng rất đơn giản.
let cell: ContactTableViewCell = self.tableView.on_dequeue(idxPath: indexPath)
Kết
Vậy là xong, chúng ta có thể làm gọn việc khai báo và sử dụng cell trong tableView đỡ phức tạp đi 1 tý. Có thể áp dụng cách trên với collection view. Các bạn có thể down demo tại đây Bài viết có nguồn từ https://kipalog.com/posts/Slim-tableview
All rights reserved