动态改变 UITableViewCell 高度 - Swift 4
Posted
技术标签:
【中文标题】动态改变 UITableViewCell 高度 - Swift 4【英文标题】:Dynamically change UITableViewCell height - Swift 4 【发布时间】:2018-09-10 22:22:42 【问题描述】:如何动态更改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
【问题讨论】:
错误是什么? 线程 1:致命错误:在展开可选值时意外发现 nil 问题出在as!
。我在下面的回答将帮助您找到正确的方向。
澄清一下,tableView.cellForRow(at: indexPath)
返回 nil。所以在给定的路径上没有单元格。将其更改为 as?
并检查 nil 并且此代码可能有效。不过,我强烈建议使用“计算器单元”方法。
我将 as!
更改为 as?
并使用 if 检查它是否不为零。它有效,但高度仍然不正确。也许我的getHeight
函数有错误?
【参考方案1】:
请记住 UITableViewCell 被重用。所以获取当前单元格的高度可能是不稳定的。
一种更好的方法是使用一个假/占位符单元格(我称之为计算器单元格)并使用它来计算单元格的大小。
所以在 heightForRowAt 方法中,您获取的是数据而不是单元格。 将该数据放入计算器单元格中,然后从那里获取高度。
【讨论】:
那么在 heightForRowAt 方法中,我如何创建一个calculatorCell
?我正在尝试实现此方法,但我认为我遗漏了一些东西
@yambo,给你的视图控制器一个属性,一个缓存的单元格,你可以用它来执行计算【参考方案2】:
你的代码因为这一行而崩溃
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)
希望对你有帮助。
【讨论】:
谢谢!我没有意识到调用这些委托方法的顺序,这解释了很多。使用您建议的解决方案,如果尚未创建单元格并且您没有在该方法中创建单元格变量,我如何引用yourCellTitle
?对不起,我的误解,我非常了解编码。
@yambo 您必须有一些容器,其中包含您将使用UITableView
显示的内容。我已经编辑了我的答案并添加了一个更详细的示例。不要担心误解。这是使用UITableView
的基础知识,您可以在网上找到很多教程。
您的解决方案非常适合UILabel
在“高度”中只有 1 行的单元格!对于高度超过 1 行的标签,我不确定如何正确使用此方法。有没有办法将字符串长度与标签宽度进行比较,看看字符串是否会在标签中超过1行?
@yambo 来自字符串扩展的方法已经 计算多行字符串的高度。如果它总是返回单行的高度,则您可能传递了错误的参数。你如何计算你的标签宽度?
我正在以编程方式做所有事情,并使用锚属性使我的标签成为屏幕宽度的一半。所以由于标签填满了屏幕的一半,我通过UIScreen.main.bounds.width * 0.5
作为宽度【参考方案3】:
你没有提到你是否使用自动布局,但如果你是,你可以让自动布局管理每一行的高度。你不需要实现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
【讨论】:
以上是关于动态改变 UITableViewCell 高度 - Swift 4的主要内容,如果未能解决你的问题,请参考以下文章
带有图像视图和标签的 iOS UITableViewCell 动态大小的表格视图单元格