“`html

簡要

在本教學中,我們將探討如何使用 Swift 來實現 UICollectionView 中的自適應寬度。自適應寬度在許多應用場景中都非常重要,尤其是在顯示動態內容時。今天,我們將學習如何根據文本長度自動調整 cell 的寬度。

設定 UICollectionView

要控制 cell 的大小,我們首先需要設置 collection view 的 layout。我們可以使用以下代碼來設置 cell 的基本大小:

layout.itemSize = CGSize(width: 100, height: 30)

若希望對每個 index row 的 cell 大小進行更細緻的控制,我們可以實作 collection view layout 的 delegate 方法,來動態返回每個 cell 的 CGSize。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    var cellSize = CGSize()
    return cellSize
}

請注意,這需要在類別宣告中遵循 UICollectionViewDelegateFlowLayout 協議,這樣才能使用這些方法。

class HomeViewController: UIViewController, UICollectionViewDelegateFlowLayout {}

數據準備

接下來,我們需要準備一個包含篩選標題的數組:

var filterTitleArr: [String] = ["分類", "價格範圍", "外送費上限", "飲食限制"]

每個篩選標題的長度不同,因此我們需要測量每個文字的寬度。以下是自定義的 textSize 方法,可以根據字體和最大尺寸來計算文本的大小:

// MARK: - Custom Methods
func textSize(text: String, font: UIFont, maxSize: CGSize) -> CGSize {
    return text.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], attributes: [NSAttributedString.Key.font: font], context: nil).size
}

計算 Cell 尺寸

現在,我們回到 collectionViewLayout 的方法中,利用剛剛的 textSize 方法來計算每個 cell 的寬度,並返回相應的 CGSize:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let textFont = UIFont.systemFont(ofSize: 17)
    let textString = filterTitleArr[indexPath.item]
    let textMaxSize = CGSize(width: 240, height: CGFloat.greatestFiniteMagnitude)
    let textLabelSize = self.textSize(text: textString, font: textFont, maxSize: textMaxSize)

    // +40 是右方 icon 寬度 + 其他設定
    let cellSize = CGSize(width: textLabelSize.width + 40, height: 30)
    return cellSize
}

在 cellForItemAt indexPath 方法中,我們將文本設置到 cell 中:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell: HomeCell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! HomeCell
    cell.textLabel.text = filterTitleArr[indexPath.item]
    cell.iconImg?.image = UIImage(named: "down")
    return cell
}

動態顯示篩選標題

若要讓第一個 cell 顯示為圓形並保持樣式一致,我們可以在 layout 方法中進行判斷:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let cellSize: CGSize
    if indexPath.item == 0 {
        cellSize = CGSize(width: 30, height: 30) // 圓形
    } else {
        // 繼續使用之前的計算邏輯
    }
    return cellSize
}

最佳實踐:避免記憶體問題

在使用 UIImageView 時,最好避免每次重複添加新圖片,這樣會導致記憶體使用過高。可以考慮使用 UIStackView 來組織你的元件,以便更好地管理顯示和隱藏。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell: HomeCell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! HomeCell

    if indexPath.item == 0 {
        // 隱藏文字和 icon
    } else {
        // 顯示文字和 icon
    }

    return cell
}

簡單 Demo
UICollectionView 自適應寬度示範

原 APP
原 APP 界面

大功告成!現在你已經掌握了如何在 Swift 中實現 UICollectionView 的自適應寬度。

Q&A(常見問題解答)

Q1: UICollectionView 的自適應寬度有什麼實際應用?

A1: 自適應寬度可以用於顯示動態內容,如標籤、選單等,確保用戶界面整潔且易於使用。

Q2: 如何避免 UICollectionView 的性能問題?

A2: 確保重用 cell 並正確管理內存,例如使用 UIImageView 時避免重複添加圖片。

Q3: UICollectionViewCell 的高度可以動態調整嗎?

A3: 是的,使用 sizeForItemAt 方法可以根據內容動態返回 cell 的尺寸。

“`

Categorized in: