动态更改 UITableViewCell 高度 - Swift 4
Dynamically change UITableViewCell height - Swift 4
如何动态更改 UITableViewCell
高度?我试过执行以下操作,但由于某种原因,它不起作用。一旦我加载显示此 table 视图
的视图控制器,代码就会崩溃
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 是重复使用的。所以获取当前cell的高度会不稳定
更好的方法是使用一个 fake/placeholder 单元格(我称之为计算器单元格)并使用它来计算单元格的大小。
因此在 heightForRowAt 方法中,您获取的是数据而不是单元格。
将该数据放入计算器单元格中,然后从那里获取高度。
你的代码因为这一行而崩溃
let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
从Apple Documentation我们知道这个方法是用来做优化的。整个想法是在不浪费时间创建单元格本身的情况下获得单元格高度。所以这个方法调用before初始化任何单元格,和tableView.cellForRow(at: indexPath)
returnsnil
。因为还没有任何细胞。但是你用 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)
])
每一行都会扩展或收缩以适应标签的固有内容大小。如果设备 landscape/portrait 方向发生变化,高度会自动调整,而无需重新加载单元格。如果你希望当设备的 UIContentSizeCategory 改变时行高自动改变,设置如下:
cellLabel.adjustsFontForContentSizeCategory = true
如何动态更改 UITableViewCell
高度?我试过执行以下操作,但由于某种原因,它不起作用。一旦我加载显示此 table 视图
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 是重复使用的。所以获取当前cell的高度会不稳定
更好的方法是使用一个 fake/placeholder 单元格(我称之为计算器单元格)并使用它来计算单元格的大小。
因此在 heightForRowAt 方法中,您获取的是数据而不是单元格。 将该数据放入计算器单元格中,然后从那里获取高度。
你的代码因为这一行而崩溃
let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
从Apple Documentation我们知道这个方法是用来做优化的。整个想法是在不浪费时间创建单元格本身的情况下获得单元格高度。所以这个方法调用before初始化任何单元格,和tableView.cellForRow(at: indexPath)
returnsnil
。因为还没有任何细胞。但是你用 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)
])
每一行都会扩展或收缩以适应标签的固有内容大小。如果设备 landscape/portrait 方向发生变化,高度会自动调整,而无需重新加载单元格。如果你希望当设备的 UIContentSizeCategory 改变时行高自动改变,设置如下:
cellLabel.adjustsFontForContentSizeCategory = true