Contents
Chào bạn, chúng ta lại tiếp tục với seri Lập trình iOS cho mọi người. Bài viết này sẽ hướng dẫn bạn về TableView và sử dụng cho giao diện ứng dụng iOS.
Để nắm được bài này thì bạn cần đọc qua các bài sau:
- Protocol trong 10 phút
- Basic iOS tutorial : Delegation Pattern
- Basic iOS tutorial : Navigation Controller
Bắt đầu thôi!
Chuẩn bị
- MacOS 10.14.4
- Xcode 11.0
- Swift 5.1
1. Giới thiệu Table View
Về giao diện của ứng dụng iOS, việc hiển thị một danh sách được sử dụng rất nhiều. Hầu như đó là cốt lõi trong việc thiết kế giao diện của ứng dụng. Để hiển thị danh sách thì với iOS bạn sẽ phải dùng tới UITableView. Chúng ta nắm sơ về nó một chút:
- Table View hiển thị danh sách dữ liệu thành các hàng (row).
- Table View được tạo bởi 1 hoặc nhiều section, mỗi section sở hữu nhiều row.
- Section là số chỉ mục trong table, trong khi row là số chỉ mục trong section.
- Mỗi section có thể có section header và section footer
- Table view có 2 style: plain và grouped.
Tóm tắt:
- Hiển thị danh sách đơn thì dùng Table View với 1 section
- Hiển thị nhiều danh sách thì dùng Table View với nhiều section
Về stype hiển thị của Table View thì chúng ta có 2 kiểu chính:
- plain
- Mọi thứ được trải đều và không có sự phân tách các section với nhau
- group
- Phân tách riêng biệt các group với nhau
Ngoài ra, Table View còn có hiển thị đánh dấu chỉ mục (index). Để người dùng có thể nhanh chóng scroll tới đúng vị trí muốn tìm kiếm. Rất hữu dụng đối với danh sách quá dài.
2. Cấu trúc UITableView
2.1. Cấu trúc
Một Table View thì bao gồm những gì? Chúng ta lại tiếp tục phân tích nó.
- UITableView là subclass của UIScrollView, nên nó cho phép người dùng cuộn table. Tuy nhiên UITableView chỉ cho phép cuộc theo chiều dọc.
- Thành phần thể hiện các ô trên table là những đối tượng UITableViewCell (hay còn được gọi là cell)
- UITableView sử dụng những đối tượng UITableViewCell này để vẽ row lên table.
- Mỗi cell được xác định bởi giá trị IndexPath, IndexPath bao gồm:
section
: section trong table view mà cell đó thuộc vềrow
: chỉ mục của row trong section
Trong hình trên thì chúng ta có thể các phần giao diện cơ bản mà 1 Table View có:
- Header của Table View
- Header của Section
- Table View Cell
- Footer của Section
- Table View Cell (thuộc Section khác)
- Section
- Footer của Table View
2.2. Hoạt động
Một UITableView để hiển thị được dữ liệu từ một danh sách thì nó phải cần thêm các protocol. Trong đó:
- UITabelViewDelegate
- Với thuộc tính là
delegate
- Nhiệm vụ truyền các sự kiện và trạng thái của Table View về View Controller hay Container View nào chứa nó.
- Với thuộc tính là
- UITableViewDataSource
- Với thuộc tính là
datasource
- Nhiệm vụ là yêu cầu được cung cấp dữ liệu, như: số section, số row, title, height, cell … nhằm phục vụ cho việc hiển thị các phần tử và danh sánh.
- Với thuộc tính là
2.3. UITableViewController
UIViewController + UITableView = UITableViewController
Một class đặc biệt, là lưỡng long hợp thể của UIViewController và UITableView. Nhắm phục vụ việc lười biến của lập trình viên iOS khi muốn tạo ra 1 View Controller có sẵn 1 Table View. Bên cạnh đó, nó cũng implement sẵn các delegate
và datasource
của UITableView rồi.
Tóm tắt một chút nữa nha. Để hiển thị 1 danh sách chúng ta sử dụng UITableView. Để hiển thị UITableView thì ta có 2 cách:
- AddSubview vào 1 View nào đó
- Sử dụng UITableViewController
Bây giờ tiến sang phần code demo chút. Lý thuyết sẽ được bổ sung lần trong các ví dụ demo.
3. Simple Table View
Để cho dễ hiểu hơn thì từ phần này chúng ta sẽ kết hợp demo code với phần lý thuyết. Vì TableView dùng để hiển thị một danh sách lên trên giao diện của ứng dụng iOS. Nên bài demo chúng ta sẽ hiển thị danh sách học sinh lên màn hình.
Tạo project không sử dụng Storyboard, để có thể hiểu cách hoạt động của TableView kĩ hơn. Trong Stroryboard, nhiều thứ đã cài đặt sẵn và việc hiển thị 1 TableView lại rất đơn giản. Nếu bạn chưa biết tạo project không sử dụng Storyboard thì có thể tham khảo link sau:
Tạo tiếp 1 UIViewController với tên là HomeViewController
. Sau đó:
- Kéo thả 1 UITableView lên file
HomeViewController.xib
- Tạo 1 IBOutlet
tableview
liên kết với control vừa kéo thả ở trên
3.1. Hiển thị 1 danh sách
Để hiển thị một danh sách, thì chúng ta cần có dữ liệu cho nó. Trong ví dụ, chúng ta xét trực tiếp dữ liệu ở ViewController. Mở file HomeViewController.swift
và thêm đoạn code sau vào:
import UIKit class HomeViewController: UIViewController { var names: [String] = ["Tí", "Tèo", "Hùng", "Lam", "Thuỷ", "Tuấn", "Trung", "Hạnh"] @IBOutlet weak var tableview: UITableView! override func viewDidLoad() { super.viewDidLoad() title = "Home" } }
-
- Danh sách hiển thị là 1 array String.
Để hiển thị lên TableView thì cần thực hiện một số bước sau:
- Bước 1: Register Cell
- Trong 1 danh sách, thì có rất nhiều phẩn tử và để xác định phần tử đó hiển thị như thế nào, tức là tương ứng với một loại
cell
nào. Thì cần phảiregister cell
cho TableView.
- Trong 1 danh sách, thì có rất nhiều phẩn tử và để xác định phần tử đó hiển thị như thế nào, tức là tương ứng với một loại
override func viewDidLoad() { super.viewDidLoad() title = "Home" //register cell tableview.register(UITableViewCell.self, forCellReuseIdentifier: "cell") }
-
- Trong đó:
register
có 2 kiểu đăng ký- Thông qua
class
- Thông qua
Nib
- Thông qua
- Các class hay Nib đều phải là sub-class của UITableViewCell
Reuse Identifier
là định danh của cell trong TableView, nhắm với 2 mục địch- Phân biết giữa các cell với nhau. Vì 1 TableView có thể chứa rất nhiều loại cell
- Tái sử dụng lại
re-use
. Vì không thể tạo ra rất nhiều đối tượng UITableViewCell để sử dụng, trong trường hợp danh sách quá dài. Vì vậy, TableView sẽ khởi tạo vài cell để hiển thị. Các cell đó sẽ được sử dụng đi, sử dụng lại với dữ liệu từ các item trong array.
- Với mỗi loại cell cần hiển thị thì chúng ta cần nhiều lần register tương ứng.
- Trong đó:
- Bước 2: Delegate & DataSource
- Bước này rất cần thiết, vì không có xét delegate & datasource thì Table View sẽ ko biết hiển thị gì.
- Chúng ta có 2 cách để xét Delegate & DataSource của TableView cho View Controller
- Code chay
override func viewDidLoad() { super.viewDidLoad() title = "Home" //register cell tableview.register(UITableViewCell.self, forCellReuseIdentifier: "cell") //delegate & datasouce tableview.delegate = self tableview.dataSource = self }
-
-
- Kéo thả
- Mở file *.xib > kích chuột phải vào TableView > kéo
dataSouce
&delegate
vàoFile's Owner
- Mở file *.xib > kích chuột phải vào TableView > kéo
- Kéo thả
-
Lưu ý: tại đây, rất nhiều bạn hay quên đi việc kéo thả và không hiểu vì sao TableView mãi không hiển thị. Thì mình khuyến cáo bạn nên dùng cách code chay để luôn luôn chạy được.
- Bước 3: Load cell
- Tạo 1
extension
choHomeViewController
và implement 2 protocol là:- UITableViewDelegate
- UITableViewDataSource
- Tạo 1
extension HomeViewController : UITableViewDelegate, UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return names.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = names[indexPath.row] return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print("selected cell: \(names[indexPath.row])") } }
-
- Để hiểu hơn, thì chúng ta có thể diễn giải chúng qua một số câu hỏi của UITableView cho ViewController như sau:
numberOfSections
:- Hỏi: Có bao nhiêu danh sách cần hiển thị?
- Trả lời: 1
numberOfRowsInSection
:- Hỏi: Có bao nhiêu phần tử cần hiển thị có từng danh sách?
- Trả lời: toàn bộ danh sách
names
cellForRowAt indexPath
:- Hỏi: Tôi cần 1 cell, ông Controller cho tôi loại cell nào đây? Tôi có thứ tự của cell là
indexPath
- Trả lời: lúc nãy mi vừa đăng ký class
UITableViewCell
rồi, tao sẽ trả có mi cell loại đó. Dữ liệu mới là phần tử trongnames
với thứ tự làindexPath
- Hỏi: Tôi cần 1 cell, ông Controller cho tôi loại cell nào đây? Tôi có thứ tự của cell là
didSelectRowAt indexPath
:- Hỏi: Thèn người dùng vừa chọn vào cell của tao (TableView), ta báo cho mi (ViewController) biết. Thứ tự cell nó chạm là
indexPath
- Trả lời: OK, I am fine.
- Hỏi: Thèn người dùng vừa chọn vào cell của tao (TableView), ta báo cho mi (ViewController) biết. Thứ tự cell nó chạm là
- Để hiểu hơn, thì chúng ta có thể diễn giải chúng qua một số câu hỏi của UITableView cho ViewController như sau:
Kết quả thực thi:
Rất đơn giản để hiển thị 1 danh sách. Ahihi!
3.2. Hiển thị nhiều danh sách
Đôi lúc, chúng ta lại cần hiển thị nhiều danh sách trong cùng 1 màn hình. Chúng có thể liên quan hay không liên quan với nhau. Trong bài, ta cho 2 danh sách và được tổ chức dữ liệu như sau:
var names: [[String]] = [ ["Tí", "Tèo", "Hùng", "Lam", "Thuỷ", "Tuấn", "Trung", "Hạnh"], ["Bình", "Khánh", "Toàn", "Tâm", "An", "Hương", "Huy", "Quang", "Vân", "Đài", "Tiến"] ]
Trong đó:
names
được khai báo là 1 Array với mỗi phần tử lại là 1 Array String. Mãng 2 chiều String
Tiếp theo, cập nhật lại các delegate và datasouce để load dữ liệu cho phù hợp. Tham khảo đoạn code sau:
extension HomeViewController : UITableViewDelegate, UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return names.count } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return names[section].count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = names[indexPath.section][indexPath.row] return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print("selected cell: \( names[indexPath.section][indexPath.row])") } }
Chú ý:
- Để thao tác với dữ liệu là nhiều danh sách, thì sử dụng
indexPath.section
- Để lấy được giá trị của các phần tử thì kết hợp cả
section
vàrow
để truy xuất tới mãng 2 chiềunames[indexPath.section][indexPath.row]
Build thử và xem kết quả:
Như thế này, thì chúng ta không biết được, phần tử nào thuộc danh sách nào. Vì vậy, để phân biệt chúng thì chúng ta có 2 cách.
- Cách 1: Chuyển trạng thái hiển thị của TableView sang
group
- Kiểu:
group
- Kiểu:
Chọn style
tại fle *.xib
Kết quả hiển thị, thì vẫn khó phân biệt các danh sách với nhau.
-
- Kiểu:
inset group
- Kiểu:
Kiểu này thì hiển thị đẹp hơn, các danh sách rất rõ ràng.
- Cách 2: Thêm
title
vào mỗi section- Reset
style
về lại plain - Mở file
HomeViewController.swift
, thêm dữ liệu chotitle
- Reset
var titles: [String] = ["iOS", "Android"]
-
- Thêm function sau vào extension của Delegate & DataSource
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return titles[section] }
Kết quả như sau:
Bây giờ, thì đã hiển thị được nhiều danh sách với title của chúng. Tiếp theo khám khá thêm việc áp dụng TableView vào trong việc điều hướng với mô hình Master – Detail.
4. Master – Detail
Tạo một ViewController, với tên là DetailViewController
. Có
- 1 UILabel
- 1 IBOutlet cho Label đó
Cập nhật thêm cho DetailViewController
import UIKit class DetailViewController: UIViewController { @IBOutlet weak var nameLabel: UILabel! var name: String = "" override func viewDidLoad() { super.viewDidLoad() title = "Detail" nameLabel.text = name } }
- Biến
name
sẽ lưu trữ dữ liệu từmaster
- UILable sẽ cập nhật dữ liệu từ biến
name
, tại hàmviewDidLoad
Tiếp tục với file HomeViewController.swift
, tại hàm didSelectRowAt indexPath
. Chúng ta làm các công việc sau:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { print("selected cell: \( names[indexPath.section][indexPath.row])") //1 let vc = DetailViewController() //2 vc.name = names[indexPath.section][indexPath.row] //3 self.navigationController?.pushViewController(vc, animated: true) }
Trong đó:
- Tạo một đối tượng của
DetailViewController
- Xét giá trị cho
name
của detail, bằng giá trị từ phần tử của mãng 2 chiềunames
- Push detail vào, chú ý tạo
rootViewController
của window là 1UINaviagtionController
Kết quả
Master – Detail là mô hình khá phổ biến trong lập trình iOS. Với điều hướng đơn giản bằng UINavigationController
. Trong đó, các thành phần chính:
- Master
- UITableView
- Chịu trách nhiệm hiển thị 1 danh sách hoặc nhiều danh sách
- Detail
- ViewController
- Chịu trách nhiệu hiển thị chi tiết 1 phần tử của danh sách
Đối với iPad thì sẽ có cách hiển thị khác là UISplitViewController
. Để phù hợp với kích thức màn hình hớn. Tới đây, thì chúng ta đi qua cơ bản về UITableView.
Tạm kết
- Tìm hiển về UITableView
- Cấu trúc và hoạt động
- Simple Table View
- Section
- Master – Detail
Phần tiếp theo của TableView:
- Basic iOS tutorial : Custom Cell
- (đang cập nhật)
Cảm ơn bạn đã đọc bài viết này!
Related Posts:
Written by Thinh Chym
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)