iOS UITableViewController 单元格在第一次更改时调整单元格高度后跳出位置

iOS UITableViewController cells jumping out of place after resizing cell heights on first change

更新:看起来 tableView.estimatedRowHeight 设置与问题有某种关系,因为问题的方差随着数字的变化而变化,将其设置为 9999 会使它 "go away" 但是看起来超级hacky。 9999 也打破了我打算在 show/hide 上做的动画。 9999 还破坏了滚动条的功能。有关更多详细信息和完整上下文,请参阅下面的讨论主题。

我有一个包含两个 Container Views 的视图控制器。每个容器视图都包含一个 UITableView 控制器。它们垂直放置,每个都占据整个高度。

右侧的容器宽度为 100,从屏幕开始,尾随约束设置为 -100,这允许另一个容器最初填满整个屏幕。

左侧的 table 使用 UITableViewAutomaticDimension 自动调整单元格高度,因为当显示隐藏视图时,两行上的某些文本可能需要换行。

当我将约束更改为 0 并显示视图时,如果我不在列表的顶部,而不是扩展屏幕上可见的内容,它似乎在扩展所有内容,从而推动了原来的内容在屏幕上向下,比它应该走的更远。

但奇怪的是,后续 expand/collapses 是否按预期工作,仅调整可见部分。

我附上了一个视频来展示这个问题,我只是想把事情联系起来,让大小调整工作,正确视图中的内容最终会有所不同。

以下是视频中发生的事情

  1. 我从列表的顶部 expand/collapse 并且按预期工作
  2. 我滚动到列表的中间并展开,但我的内容被向下推得比它应该的更深。
  3. 然后我再次折叠并展开它,这次它留在原处,因为可见屏幕上的尺寸没有改变。

无论我在列表中往下走多远,相同的行为都会发生,越往下越糟。

我现在正在按这样的按钮调整约束。

   if self.timeContainerConstraint.constant == 0 {
        self.timeContainerConstraint.constant = -90.0
   } else {
        self.timeContainerConstraint.constant = 0.0
   }

有谁知道为什么我第一次向下滚动列表并展开时内容会跳转,但在后续尝试时不会跳转?

由于单元格高度可变,table视图在其框架发生变化时无法正确计算滚动偏移量。它必须依赖估计的行高,但是因为你有一个固定的值,所以当前滚动位置的单元格越多'above',估计值和实际值之间的误差就越大。

我能够通过缓存单元格高度来解决这个问题,以便使用 estimatedHeightForRowAt:

return 更准确的估计高度
var cellHeights = [IndexPath:CGFloat]()

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let frame = tableView.rectForRow(at: indexPath)

    self.cellHeights[indexPath] = frame.size.height

}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return self.cellHeights[indexPath] ?? 140.0
}

使用这种方法,侧边栏的扩展和收缩不会影响 table 的位置。我能够为约束变化设置动画以获得平滑的显示效果,而 table 没有 'jump',即使 table 在边栏打开时滚动。

我的示例项目是here