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 chuotfx on November 19, 2019

Basic iOS tutorial : Custom Cell

iOS & Swift

Contents

  • Chuẩn bị
  • 1. Add Subview
    • Nguyên tắc làm việc với reuseable như sau:
  • 2. Custom Cell
    • 2.1. Create cell
    • 2.2. Register Cell
    • 2.3. Load cell
  • 3. Dynamic cell
  • Tạm kết

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:

    • Basic iOS tutorial : Table View

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:

    • Basic iOS tutorial : 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ủa reuseable.

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

  1. Tạo 1 đối tượng nib, với tên nibName chính là tên file *.xib. Bundle chính là main bundle
  2. Sử dụng hàm register với nib
  3. 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ới identifier 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 đó:

  1. Tạo 1 array user rỗng
  2. Lặp từ 0 đến 30 lần
  3. Tạo mới 1 đối tượng user với dữ liệu cung cấp là random
  4. 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

 

FacebookTweetPinYummlyLinkedInPrintEmailShares3

Related Posts:

  • Basic iOS tutorial : Custom View
    Basic iOS tutorial : Custom View
  • Basic iOS tutorial : Touch Event
    Basic iOS tutorial : Touch Event
  • Basic iOS tutorial : MVC
    Basic iOS tutorial : MVC
  • Basic iOS tutorial : Stack View
    Basic iOS tutorial : Stack View
Tags: basic ios tutorial, iOS, tableview
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

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

Donate – Buy me a coffee!

Recent Posts

  • Map type – Dart Tour
  • Set type – Dart Tour
  • List type – Dart Tour
  • Null safety – Dart Tour
  • Classes & Objects – Dart Tour
  • Quick trong 10 phút
  • Nimble trong 10 phút
  • Functions – Dart Tour
  • Control Flow – Dart Tour
  • API Testing (UnitTest) with OHHTTPStubs

Fan page

Fx Studio

Archives

  • August 2022 (4)
  • 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)

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

You may also like:

  • Basic iOS tutorial : Delegation Pattern
    Basic iOS tutorial : Delegation Pattern
  • Basic iOS tutorial : MVC
    Basic iOS tutorial : MVC
  • Basic iOS tutorial : Stack View
    Basic iOS tutorial : Stack View
  • Basic iOS tutorial : MVVM
    Basic iOS tutorial : MVVM
  • Basic iOS tutorial : Custom View
    Basic iOS tutorial : Custom View

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 (20)
  • Code (4)
  • Combine (22)
  • Flutter & Dart (16)
  • iOS & Swift (83)
  • RxSwift (37)
  • SwiftUI (75)
  • Tutorials (69)

Newsletter

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

Copyright © 2022 Fx Studio - All rights reserved.

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

Email sent!