如何动态更改UITableViewCell
的高度?我尝试实现以下内容,但由于某种原因,它无法正常工作。一旦加载显示此表视图的视图控制器,代码便会崩溃
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
return cell.getHeight()
}
这是我的getHeight
中的AvailableRideCell
函数
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
}
}
}
答案 0 :(得分:1)
请记住,UITableViewCell已被重用。因此获取当前单元格的高度可能会很不稳定。
一种更好的方法是使用一个伪造/占位符单元格(我称为计算器单元格),并使用该单元格来计算该单元格的大小。
因此,在heightForRowAt方法中,将获取数据而不是单元格。 将这些数据放入计算器单元格,然后从那里获取高度。
答案 1 :(得分:0)
您的代码由于此行而崩溃
let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
根据Apple Documentation,我们知道此方法用于优化。整个想法是在不浪费时间创建单元本身的情况下获得单元高度。因此,这种称为 before 的方法将初始化任何单元格,并且tableView.cellForRow(at: indexPath)
返回nil
。因为还没有任何单元格。但是您用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)
希望它对您有帮助。
答案 2 :(得分:0)
您没有提到是否使用自动版式,但如果使用自动版式,则可以让自动版式管理每行的高度。您无需实现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