[英]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()
}
這是我的AvailableRideCell
的getHeight
函數
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.