重新加载单元格后向上滚动时,动态单元格高度跳跃的UITableView

And*_*rew 14 objective-c uitableview ios swift

我有一个表格视图,每个单元格有可能有自己的高度,因此不适合使用rowHeight.相反,现在我正在使用let indexSet = NSIndexSet(index: 10),而且self.tableView.estimatedRowHeight = 75.这意味着它调用sizeThatFits单元格上的函数,以确定其高度.这一切都运作良好.

问题是当你重新加载屏幕上的单元格时.例如,向下滚动以显示单元格10,然后重新加载单元格10,工作正常.但是当你开始向上滚动,经过你已经看过的单元格时,它会恢复到每个单元格的estimatedRowHeight,完全忽略sizeThatFits,因此在滚动时跳转.我不可能给出一个准确或"足够好"的估计值,因此这种跳跃不会引人注意,因为我的细胞能够显示一行文字或一个完整的图像 - 这是一个很大的区别.尺寸.

我在这里展示了这个效果:

https://vid.me/edgW

我在这方面做了很多不同的尝试,使用了heightForRowAtIndexPath,estimatedHeightForRowAtIndexPath等的混合物.我在StackOverflow上尝试了各种建议.似乎没什么用.

我附上了一个非常简单的示例项目,您可以自己尝试:

https://www.dropbox.com/s/8f1rvkx9k23q6c1/tableviewtest.zip?dl=0

  1. 运行该项目.
  2. 滚动,直到查看单元格10.
  3. 等待最多5秒钟让细胞重新加载(它变成紫色).
  4. 向上滑动.

值得注意的是 - 如果单元格在重新加载时不在视图中,则不会发生这种情况.如果它高于低于当前滚动点,则一切都按预期工作.

zwa*_*ski 17

这种行为似乎是一个错误,如果没有其他原因,它不再可以在iOS 9上重现.我敢肯定,这不是什么安慰.

这个问题主要来自于一个不准确的估计,如@NickCatib所说.你可以在iOS 8上做的最好的事情就是改进估算.许多人建议的技术是willDisplayCell在后续调用中缓存高度并使用它们estimatedRowHeightAtIndexPath.

您可以通过不做任何事情来UITableView放弃其缓存来缓解行为,例如通过直接使用单元格修改内容cellForRowAtIndexPath而不是使用重新加载(如果它在屏幕上).但是,如果您确实需要更改单元格的高度,那将无济于事.

我不敢说在桌面视图中不能轻易修复bug,因为你无法控制布局.UICollectionViewFlowLayout通过更改contentOffsetAdjustment失效期间的错误可以更容易地在子类中解决,尽管这可能不是非常容易.


Pra*_*y C 11

我也有这个问题,并使用了SO的解决方案,我现在无法找到.如果我这样做,我会添加链接.这是解决方案:

问题是表格视图没有正确的行高估计.要修复它,最初缓存高度,willDisplayCell然后再使用该高度.

在viewDidLoad中:

heightAtIndexPath = [NSMutableDictionary new];


- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber *height = @(cell.frame.size.height);
    [heightAtIndexPath setObject:height forKey:indexPath];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if([heightAtIndexPath objectForKey:indexPath]) {
        return [[heightAtIndexPath objectForKey:indexPath] floatValue];
    } else {
        return UITableViewAutomaticDimension;
    }
}
Run Code Online (Sandbox Code Playgroud)


SM *_*sif 5

在 iOS 13.5.1 中:

我有一个 tableView,其中包含 4 种类型的单元格,所有这些单元格都具有不同的动态高度。我在这里遵循了公认的解决方案,但要解决跳跃效果,我需要在重新加载表视图时添加更多内容:

从接受的答案中,我添加了以下代码:声明此变量

var allCellHeights = [IndexPath : CGFloat]()
Run Code Online (Sandbox Code Playgroud)

然后添加2个方法:

 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
     self.allCellHeights[indexPath] = cell.frame.size.height
 }
 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
     return self.allCellHeights[indexPath] ?? UITableView.automaticDimension
 }
Run Code Online (Sandbox Code Playgroud)

现在我必须在重新加载 tableview 时添加额外的代码:

let contentOffset = self.tableView.contentOffset
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.setContentOffset(contentOffset, animated: false)
Run Code Online (Sandbox Code Playgroud)

还要检查这个答案:带有动态单元格高度的 UITableView 的 reloadData() 导致跳跃式滚动