Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Written by Thinh Chym on November 18, 2019

Basic iOS tutorial : Table View

iOS & Swift

Contents

  • Chuẩn bị
  • 1. Giới thiệu Table View
  • 2. Cấu trúc UITableView
    • 2.1. Cấu trúc
    • 2.2. Hoạt động
    • 2.3. UITableViewController
  • 3. Simple Table View
    • 3.1. Hiển thị 1 danh sách
    • 3.2. Hiển thị nhiều danh sách
  • 4. Master – Detail
  • Tạm kết

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ó:

  1. Header của Table View
  2. Header của Section
  3. Table View Cell
  4. Footer của Section
  5.  Table View Cell (thuộc Section khác)
  6. Section
  7. 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ó.
  • 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.

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:

    1. AddSubview vào 1 View nào đó
    2. 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:

    • Bắt đầu iOS Project không sử dụng Storyboard với Xcode 11 và Swift 5.1

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ải register cell cho TableView.
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
      • 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.
  • 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ào File's Owner

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 cho HomeViewController và implement 2 protocol là:
      • UITableViewDelegate
      • UITableViewDataSource
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ử trong names với thứ tự là indexPath
      • 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.

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ều
    • names[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

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 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 cho title
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àm viewDidLoad

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 đó:

  1. Tạo một đối tượng của DetailViewController
  2. Xét giá trị cho name của detail, bằng giá trị từ phần tử của mãng 2 chiều names
  3. Push detail vào, chú ý tạo rootViewController của window là 1 UINaviagtionController

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!

FacebookTweetPinYummlyLinkedInPrintEmailShares2

Related Posts:

  • RxCocoa Basic – Traits
    RxCocoa Basic – Traits
  • RxCocoa Basic – Display Data from API
    RxCocoa Basic – Display Data from API
  • Image View trong 10 phút - SwiftUI Notes #26
    Image View trong 10 phút - SwiftUI Notes #26
  • Collection View - Diffable Data Source
    Collection View - Diffable Data Source
Tags: basic ios tutorial, iOS, tableview
Written by Thinh Chym

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift api AppDistribution Asynchronous autolayout basic ios tutorial blog callback ci/cd closure collectionview combine concurrency CoreData Core Location crashlytics darkmode dart dart basic dart tour Declarative decoding delegate deploy fabric fastlane firebase flavor flutter GCD iOS mapview MVVM optional protocol rxswift Swift Swift 5.5 SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Raw String trong 10 phút
  • Dispatch Semaphore trong 10 phút
  • Tổng kết năm 2022
  • KeyPath trong 10 phút – Swift
  • Make color App Flutter
  • Ứng dụng Flutter đầu tiên
  • Cài đặt Flutter SDK & Hello world
  • Coding Conventions – người hùng hay kẻ tội đồ?
  • Giới thiệu về Flutter
  • Tìm hiểu về ngôn ngữ lập trình Dart

You may also like:

  • Image View trong 10 phút - SwiftUI Notes #26
    Image View trong 10 phút - SwiftUI Notes #26
  • RxCocoa Basic – Extend UIKit
    RxCocoa Basic – Extend UIKit
  • Collection View - Diffable Data Source
    Collection View - Diffable Data Source
  • RxCocoa Basic – Delegate Proxy
    RxCocoa Basic – Delegate Proxy
  • RxCocoa Basic – Forward Delegate
    RxCocoa Basic – Forward Delegate

Archives

  • 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)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (22)
  • Code (4)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (86)
  • RxSwift (37)
  • SwiftUI (76)
  • Tutorials (70)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2023 Fx Studio - All rights reserved.

    Share this ArticleLike this article? Email it to a friend!

    Email sent!