Contents
Chào bạn đến với Fx Studio, bài viết hôm nay sẽ là phần tiếp theo của:
Nếu bạn chưa biết về Table View thì có thể ghé link trên. Về Table View thì còn nhiều phần tiếp theo, mình xin phép chia ra thành nhiều bài với nhiều chủ đề trọng tâm. Chủ để phần này là về tuỳ chỉnh giao diện cho cell, hay giang hồ gọi với cái tên thân mật là Custom Cell
.
Bắt đầu thôi!
Về giao diện của các ứng dụng iOS, hầu như 90% đều phải tuỳ chỉnh và chúng không sử dụng các giao diện mặc định của iOS. Để tuỳ chỉnh về giao diện thì chúng ta có bài Custom View:
Vẫn nguyên tình thần của Custom View, giờ chúng ta tiến hoá sang Custom UITableViewCell (hay gọi là Custom Cell). Và cũng áp dụng nguyên các cách custom tương tự như UIView.
Chuẩn bị
- MacOS 10.14.4
- Xcode 11.0
- Swift 5.1
1. Add Subview
UITableViewCell
là class của các row (hay cell) trong UITableView. Nó là sub-class của UIView. Nên theo nguyên tắc của View, thì nó có các view con (subviews). Vì vậy, việc custom đơn giản nhất là addSubview
cho cell.
Chúng ta sử dụng lại project của phần trước. Các UITableViewCell có 1 UILabel với tên là textLabel
để hiện thị thông tin. Bây giờ, chúng ta thêm 1 label nữa để hiển thị thông tin phụ.
Mở file HomeViewController.swift
và edit đoạn code sau:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = names[indexPath.section][indexPath.row] let label = UILabel(frame: CGRect(x: 20, y: 30, width: 100, height: 20)) label.text = "sub title" label.textColor = .red cell.addSubview(label) return cell }
Trong đó:
label
là đối tượng UILabel- Xét các thuộc tính frame, text, và textColor cho
label
- AddSubView cho
cell
làlabel
Kết quả:
Quá đơn giản!
Tuy nhiên, việc xác định giao diện rất khó khắn và tối rất nhiều công sức tính toán toạ độ. Bên cạnh đó là việc re-use
thì các cell không tạo mới. Cứ như vậy, qua mỗi hàm cellForRow
chạy, thì lại có label
mới tạo ra và thêm vào, chứ chúng không bị remove đi.
Khi danh sách của bạn quá dài và scroll lên xuống nhiều lần. Với ví dụ trên, bạn sẽ thấy một số cell sẽ có màu đỏ của
sub title
đậm hơn 1 số cell khác. Đó chính là vấn đề củareuseable
.
Nguyên tắc làm việc với reuseable
như sau:
- Có
init()
thì phải códeinit()
- Có
add
thì phải córemove
- Có
if
thì phải cóelse
Và, việc addSubview không là giải pháp tối ứu nhất. Bây giờ chúng ta chuyển sang giải pháp kinh điển hơn, là kéo thả giao diện.
2. Custom Cell
2.1. Create cell
Kích chuột phải và new file, như sau:
Chú ý:
- Chọn vào
also create XIB file
để Xcode tạo sẵn cho bạn file giao diện cho Cell - Sub-class là
UITableViewCell
Tiến hành kéo thả giao diện và tạo các IBOutlet
tương ứng.
Code của file HomeCell.swift
như sau:
import UIKit class HomeCell: UITableViewCell { @IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var subTitleLabel: UILabel! override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } }
2.2. Register Cell
Mở file HomeViewController.swift
để tiến hành register
cell cho Table View. Công việc này rất quan trọng và quyết định sống còn của việc Custom Cell. Tại hàm viewDidLoad
, thêm đoạn code sau:
//1 let nib = UINib(nibName: "HomeCell", bundle: .main) //2 tableview.register(nib, forCellReuseIdentifier: "cell")
Trong đó:
- Tạo 1 đối tượng
nib
, với tênnibName
chính là tên file *.xib. Bundle chính làmain bundle
- Sử dụng hàm register với
nib
- Identifier cho cell để re-use là
cell
(bạn có thể đổi theo ý riêng của bạn)
Tới đây thì xong phần register cell cho Table View.
2.3. Load cell
Tới phần extension cho delegate của Table View trong HomeViewController.swift
. Edit lại hàm cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeCell cell.nameLabel.text = names[indexPath.section][indexPath.row] cell.subTitleLabel.text = "Sub title" return cell }
Trong đó:
- Vẫn sử dụng
dequeue
vớiidentifier
vàindexPath
để lấy đối tượng cell ra đúng với indexPath. - Ép kiểu về kiểu
HomeCell
- Xét các giá trị cho các IBOutlet của cell
Tiếp tục thêm 1 function nữa của UITableViewDelegate, mục đích:
- Xác định chiều cao của Custom Cell
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 80 }
Chạy chương trình và xem kết quả.
Nếu bạn ra được kết quả như hình, thì chúc mừng bạn đã hoàn thành việc custom cell. Tuy nhiên, vẫn còn 1 xí nữa cho phần dữ liệu của TableView.
3. Dynamic cell
Qua ví dụ trên, thì bạn sẽ thấy là:
- Dữ liệu cung cấp cho cell là 1 array String.
- Dữ liệu cần cho Custom Cell sẽ gồm nhiều trường. Tức là cần nhiều hơn 1 array.
Có thể nhiều bạn sẽ suy nghĩ như thế này để cung cấp dữ liệu cho Table View.
var names: [String] = ... var ages: [Int] = ... var genders: [Bool] = ...
Điều này thì …
Ta không thể nào tạo nhiều array để cung cấp dữ liệu cho cell. Nó làm việc quản lý dữ liệu sẽ gặp rất nhiều khó khăn. Giải pháp là nhóm tụi nó về 1 array với 1 kiểu dữ liệu mới.
Nói dễ hiểu thì tạo class/struct cho dữ liệu của Table View. Hehe!
Kích chuột phải và tiếp tục new file mới, tên là User.swift
. Trong đó:
- tạo 1 class
User
- các thuộc tính: tên, tuổi và giới tính
- hàm trả về thông tin của user
final class User { var name: String var age: Int var gender: Bool init(name: String, age: Int, gender: Bool) { self.name = name self.age = age self.gender = gender } func getSubTitle() -> String { return "\(gender ? "Male" : "Female") - \(age) year olds" } }
Tiếp tục, viết 1 function để trả về dữ liệu giả là 1 array User. Trong đó:
- Tạo 1 array user rỗng
- Lặp từ 0 đến 30 lần
- Tạo mới 1 đối tượng user với dữ liệu cung cấp là random
- Thêm đối tượng mới vào mãng.
func getUser() -> [User] { //1 var users = [User]() //2 for i in 0...30 { //3 let user = User(name: "Name \(i+1)", age: Int.random(in: 10...30), gender: Bool.random()) //4 users.append(user) } return users }
Tiến hành chỉnh sửa lại dữ liệu cho Table View của HomeViewController.swift
var users: [User] = []
Cập nhật dữ liệu cho users
override func viewDidLoad() { super.viewDidLoad() title = "Home" let nib = UINib(nibName: "HomeCell", bundle: .main) tableview.register(nib, forCellReuseIdentifier: "cell") tableview.delegate = self tableview.dataSource = self users = getUser() }
Cập nhật lại các function của delegate & datasouce của Table View.
extension HomeViewController : UITableViewDelegate, UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return users.count } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 80 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeCell let user = users[indexPath.row] cell.nameLabel.text = user.name cell.subTitleLabel.text = user.getSubTitle() return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let user = users[indexPath.row] let vc = DetailViewController() vc.name = user.name self.navigationController?.pushViewController(vc, animated: true) } }
Chú ý:
let user = users[indexPath.row]
sẽ giúp bạn lấy ra đối tượng cần thiết để hiển thị hay sử dụng dữ liệu.
Sau này, dữ liệu cũng cấp cho Table View sẽ lấy từ API/Webservice/Database … và không lệ thuộc vào việc
hardcode
. Khuyến khích khi làm việc với Table View thì nên tạo các function với dữ liệu giả để cũng cấp dữ liệu cho các cell.
Tới đây, thì bạn đã xong phần Custom Cell, hẹn gặp lại bạn ở các phần sau. Cảm ơn đã đọc!
Tạm kết
- AddSubview vào Cell
- Custom Cell
- Dynamic cell
Related Posts:
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
- Strategy Pattern trong 10 phút
- Automatic Reference Counting (ARC) trong 10 phút
- Autoresizing Masks trong 10 phút
- Regular Expression (Regex) trong Swift
You may also like:
Archives
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)