簡體   English   中英

動態更改UITableViewCell的高度-Swift 4

[英]Dynamically change UITableViewCell height - Swift 4

如何動態更改UITableViewCell高度? 我嘗試實現以下內容,但由於某種原因,它無法正常工作。 一旦加載顯示此表視圖的視圖控制器,代碼便崩潰

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
    return cell.getHeight()
}

這是我的AvailableRideCellgetHeight函數

func getHeight() -> CGFloat {
    return self.destinationLabel.optimalHeight + 8 + self.originLabel.optimalHeight + 8 + self.priceLabel.optimalHeight
}

這是optimalHeight函數

extension UILabel {
    var optimalHeight : CGFloat {
        get {
            let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude))
            label.numberOfLines = 0
            label.lineBreakMode = NSLineBreakMode.byWordWrapping
            label.font = self.font
            label.text = self.text
            label.sizeToFit()
            return label.frame.height
        }
    }
}

請記住,UITableViewCell已被重用。 因此,獲取當前單元格的高度可能會很不穩定。

更好的方法是使用一個假/占位符單元格(我稱其為計算器單元格),然后使用該單元格來計算該單元格的大小。

因此,在heightForRowAt方法中,您將獲得數據而不是單元格。 將該數據放入計算器單元格,然后從那里獲取高度。

您的代碼因此行而崩潰

let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell

Apple文檔中我們知道該方法用於優化。 整個想法是在不浪費時間創建單元本身的情況下獲得單元高度。 因此, 初始化任何單元之前調用此方法,並且tableView.cellForRow(at: indexPath)返回nil 因為還沒有任何單元格。 但是,您正在用as! AvailableRideCell解開力量as! AvailableRideCell as! AvailableRideCell和您的代碼崩潰了。

因此,首先,您需要了解 ,為什么不應該使用cellForRow(at )方法內的任何單元格。 之后,您需要更改邏輯,以便無需調用單元即可計算內容高度。

例如,在我的項目中,我使用了此解決方案

字符串實現

extension String {
    func height(for width: CGFloat, font: UIFont) -> CGFloat {
        let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
        let actualSize = self.boundingRect(with: maxSize,
                                           options: [.usesLineFragmentOrigin],
                                           attributes: [NSAttributedStringKey.font: font],
                                           context: nil)
        return actualSize.height
    }
}

UILabel實施

extension String {
    func height(for width: CGFloat, font: UIFont) -> CGFloat {
        let labelFrame = CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude)
        let label = UILabel(frame: labelFrame)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.font = font
        label.text = self
        label.sizeToFit()
        return label.frame.height
    }
}

這樣,您所需要做的就是計算標簽並存儲其字體。

var titles = ["dog", "cat", "cow"]

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // number of rows is equal to the count of elements in array
    return titles.count
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cellTitle = titles[indexPath.row]
    return cellTitle.height(forWidth: labelWidth, font: labelFont)
}

動態行高變化

如果您需要更新行高,那么您要做的就是在更改內容后調用此方法。 indexPath是已更改項目的索引路徑。

tableView.reloadRows(at: [indexPath], with: .automatic)

希望對您有幫助。

您沒有提到是否使用自動版式,但是如果您使用自動版式,則可以讓自動版式管理每行的高度。 您不需要實現heightForRow ,而是設置:

tableView.rowHeight = UITableViewAutomaticDimension

並使用將其固定到單元格內容視圖的約束條件配置UILabel:

    let margins = contentView.layoutMarginsGuide
    NSLayoutConstraint.activate([
        cellLabel.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
        cellLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor),
        cellLabel.topAnchor.constraint(equalTo: margins.topAnchor),
        cellLabel.bottomAnchor.constraint(equalTo: margins.bottomAnchor)
    ])

每行都會擴展或收縮以適合標簽固有內容的大小。 如果設備橫向/縱向改變,則高度會自動調整,而無需重新加載單元。 如果您希望當設備的UIContentSizeCategory更改時行高自動更改,請設置以下內容:

cellLabel.adjustsFontForContentSizeCategory = true

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM