UITableViewCell remake constraints when reuse 问题

UITableViewCell remake constraints when reuse problem

我在重复使用单元格时遇到问题。

在我的单元格中,有一个视图会根据其状态更改约束。默认情况下,单元格高度 = 0,当用户单击按钮时,它会更改其约束顶部、前导、尾随和底部。问题是,如果我展开,在一个单元格中按下展开视图,向下(或向上)滚动,那么另一个单元格也会被展开。

我在 prepareForReuse 方法中更改了负责发现单元格的变量,但没有帮助:(

我的解决方案以前是这样的:我重做了configure方法中的constraints(在VC中的cellForRow方法中调用了),成功了, BUT 显然,滚动时有滞后,因为每次配置和重用单元格时我都会更改约束 有没有办法避免滚动时出现滞后?还有其他方法吗?

我使用 SnapKit 进行布局。

我会尽量避免让单元格的高度为零。这可能会扰乱 table 视图并在多种情况下产生开销。由于单元格出列以减少资源消耗,因此您不应生成大小为零的单元格,因为理论上您可以在屏幕上看到无限数量的此类单元格。所以基本上你可以很容易地遇到这样一种情况,即你的 table 视图正在处理数百个单元格,而用户甚至看不到。

零高度单元格的替代方法是 table 视图中的 insert/delete 单元格。甚至已经有了相应的动画。为此,您需要更正 numberOfRows 方法和 cellForRowAt 方法,它们都需要忽略“隐藏”单元格。除此之外,你基本上只需要像

这样的东西
func hideCell(indexPath: IndexPath) {
    tableView.beginUpdates()
    self.items[indexPath].isHidden = true
    tableView.deleteRows(at: [indexPath], with: .automatic)
    tableView.endUpdates()
}

func showCell(indexPath: IndexPath) {
    tableView.beginUpdates()
    self.items[indexPath].isHidden = false
    tableView.insertRows(at: [indexPath], with: .automatic)
    tableView.endUpdates()
}

这应该可以解决您的大部分(全部)问题。但是,如果您仍想保留 small/zero 大小的单元格,还有其他方法可以解决您的问题。

当您更改约束时,您还应该调用(也许您已经这样做但没有 post 它)

cell.remakeParentCommentConstraints()
tableView.beginUpdates()
tableView.endUpdates()

并确保在调用 cellForRow 时你也调用 cell.remakeParentCommentConstraints() 因为当单元格出列时你无法知道前一个单元格处于什么状态。

即使正确执行所有这些操作,您也可能会跳跃。这是因为默认情况下估计高度逻辑不是很智能,您需要对其进行改进。一个快速的解决方法是缓存你的单元格高度:

private var cellHeightCache: [IndexPath: CGFloat] = [:]

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return cellHeightCache[indexPath] ?? 44.0
}

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    cellHeightCache[indexPath] = cell.bounds.height
}

带有44.0的部分应该是您当前设置的估计行高。 如果你 insert/delete 行(如第一个解决方案),这个技巧可能会变得有点复杂。因为您还需要 insert/remove 来自缓存的高度。这是可行的,只是不那么容易。

我通过将状态分成不同的单元格解决了这个问题