UITableViewCell内容在单独重新加载单元格时闪烁

M. *_*ani 6 performance objective-c uitableview ios asyncdisplaykit

我有一个链接到a的表视图NSFetchedResultController(即加载数据并跟踪数据的更改绑定到FRC)

我没有AutoLayout在我的单元格中使用(由于它在iOS 8中引入的巨大性能下降).我在单元格中手动布置我的单元格内容(使用-(void)layoutSubviews).另外,行的高度是根据内容计算的,并且正确缓存/无效.

如果与我的数据相关的任何条件发生更改,相关单元格将单独更新(-(void)controllerWillChangeContent:...通过-(void)controllerDidChangeContent:...实现整个委托方法),行更新的动画为:UITableViewRowAnimationNone

这里的问题是,我的细胞有透明背景,我可以看到一些视觉噪声(很可能是实际的细胞被垂直拉伸,我不能肯定地说,因为它们真的是短暂的和短暂的)[self.tableView reloadRowsAtIndexPaths:...];.

我尝试过很多东西都无济于事!

以下是我尝试过的不起作用的内容:

  • 实施-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath,返回估计高度的准确值.
  • 设置self.tableView.rowHeight=UITableViewAutomaticDimension;,帮助很多,但没有解决它.
  • 禁用动画[self.tableView beginUpdates];并启用之后[self.tableView endUpdates];
  • 删除单元格内容中的所有子视图 -(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

有点帮助的事情:

  • 使细胞不透明(即为细胞设置背景颜色).奇怪的是,工件似乎在实际的单元格内容之下.

更多信息

  • 我的大部分单元格内容都来自AsyncDisplayKit(ASTextNode,ASImageNode),但是用它们替换它们UIKit并不能解决问题.
  • 我的所有视觉更新都发生在主线程上.我总是确保这一点.
  • 问题并不是普遍存在,而是经常存在.如果它有帮助,它们似乎在插入第二个细胞后发生更多.
  • -(void)layoutSubviews在我的单元格中记录该方法表明,每次更新时,具有更新条件的单元格会连续重新加载3次,而其他单元格只会更新一次.我不是强迫任何[cell layoutIfNeeded];[cell setNeedsLayout];任何地方.
  • 重新加载整个表视图[self.tableView reloadData];不是我的选择.

更多信息

  • 使细胞变得不透明导致细胞只被布置一次!奇怪的!

最后,我很抱歉我不能分享任何实际的代码,因为它不是一个测试项目,并且实现的复杂性使得任何代码共享都是徒劳的,除非作为一个整体被理解.

谢谢你的时间.

San*_*ndy 21

我在使用reloadRowsAtIndexPath时也遇到了闪烁UITableViewCell的问题,所以我做的是 -

     [UIView setAnimationsEnabled:NO];
     [self.tableView beginUpdates];

     [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
                                               withRowAnimation:UITableViewRowAnimationNone];
     [self.tableView endUpdates];
     [UIView setAnimationsEnabled:YES];
Run Code Online (Sandbox Code Playgroud)

重新加载单元格时,上面的代码片段在单元格上没有动画.

  • 亲爱的@Sandy,我知道上面的解决方案,但是很遗憾,我的表格视图接收到的更新频率更高,并且它与其他类型的更新(插入,删除,移动)混合在一起,我不想丢掉其他动画。另外,我的问题与动画本身无关,这是我的错误。谢谢你的时间。 (2认同)

Ant*_*ior 12

是的,您可以使用performWithoutAnimation(Swift版本)从@Sandy的答案中获得类似的结果

UIView.performWithoutAnimation {
      self.tableView.reloadRows(at: [indexPath], with: .none)
}
Run Code Online (Sandbox Code Playgroud)


M. *_*ani 5

如果有人遇到同样的问题:

如果要计算单元格高度及其元素,并且依赖于NSIndexPath查询任何数据或条件,请始终检查索引路径是否有效(不是nil).UITableView返回索引路径的大多数方法(例如-(NSIndexPath *)indexPathForCell:..,等等)可能会返回nil值,并将向您射击调试视图的螺旋.

在我的情况下,我有一个方法来确定我的单元格是否应该有一个标题,为此我检查了它是第一个单元格或条件自上一个单元格以来已经改变.indexPath.row == 0即使索引路径实际存在,问题也是如此nil(它是Objective-C中的概念问题,其中nil0).所以在短暂的一刻,我的细胞会认为它有一个标题!

我觉得有点愚蠢没有检查nil索引路径,但我认为分享它可能有一天会帮助某人.