UITableViewCell 内容在单独重新加载单元格时闪烁
UITableViewCell content flickers while reloading cells individually
我有一个链接到 NSFetchedResultController
的 table 视图(即加载数据和跟踪数据更改绑定到 FRC)
我没有在我的单元格中使用 AutoLayout
(由于它在 iOS 8 中引入的巨大性能下降)。我在单元格中手动布置单元格的内容(使用 -(void)layoutSubviews
)。另外,行高是根据内容计算的,并且 cached/invalidated 正确。
如果与我的数据相关的任何条件发生变化,相关单元格将单独更新(实现整个 -(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];
重新加载整个 table 视图对我来说不是一个选项。
其他更多信息
- 使单元格不透明会导致单元格只布置一次!奇怪!
最后,很抱歉我不能分享任何实际代码,因为它不是一个测试项目,而且实现的复杂性使得任何代码共享都是徒劳的,除非作为一个整体来理解。
感谢您的宝贵时间。
如果有人遇到同样的问题:
如果您正在计算单元格高度及其元素,并且您依赖 NSIndexPath
来查询任何数据或条件,请始终检查您的索引路径是否有效(而不是 nil
)。 return 索引路径(例如 -(NSIndexPath *)indexPathForCell:..
等)的大多数 UITableView
方法可能 return nil
值,并且会让你陷入调试视图的螺旋.
在我的例子中,我有一个方法来确定我的单元格是否应该有一个 header,为此我检查了它是第一个单元格还是自上一个单元格以来条件发生了变化。问题是 indexPath.row == 0
是真的,即使索引路径实际上是 nil
(这是 Objective-C 中的概念问题,其中 nil
是 0)。所以有那么一小会儿我的细胞会认为它有 header!
我觉得不检查 nil
索引路径有点愚蠢,但我认为分享它可能有一天会对某人有所帮助。
我在使用 reloadRowsAtIndexPath 时也遇到了 UITableViewCell 闪烁的问题,所以我所做的是 -
[UIView setAnimationsEnabled:NO];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
[UIView setAnimationsEnabled:YES];
上面的代码片段在重新加载单元格时不会在单元格上显示动画。
我在 swift 中使用它,它减少了闪烁
let visibleIndexs = self.ContentTableview.indexPathsForVisibleRows! as NSArray
print(visibleIndexs)
for indx in visibleIndexs {
if self.imgDownloadedIndexs!.containsObject(indx) {
UIView.setAnimationsEnabled(false)
self.ContentTableview.beginUpdates()
self.ContentTableview.reloadRowsAtIndexPaths([indx as! NSIndexPath], withRowAnimation:.None)
self.ContentTableview.endUpdates()
UIView.setAnimationsEnabled(true)
self.imgDownloadedIndexs?.removeObject(indx)
}
是的,您可以使用 performWithoutAnimation
(Swift 版本)
从 @Sandy 的回答中获得类似的结果
UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none)
}
删除 rowHeightAtIndexPath 方法将解决此问题。确保您已为情节提要中的 table 单元格设置了一些固定高度。
tableView 自定义单元格不可点击且闪烁。这是因为细胞动画。添加以下代码后,单元格可以点击并且工作正常。
这种情况正常发生,也可能发生在运行 UITestCase.
时
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none)
}
return cell
}
我有一个链接到 NSFetchedResultController
的 table 视图(即加载数据和跟踪数据更改绑定到 FRC)
我没有在我的单元格中使用 AutoLayout
(由于它在 iOS 8 中引入的巨大性能下降)。我在单元格中手动布置单元格的内容(使用 -(void)layoutSubviews
)。另外,行高是根据内容计算的,并且 cached/invalidated 正确。
如果与我的数据相关的任何条件发生变化,相关单元格将单独更新(实现整个 -(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];
重新加载整个 table 视图对我来说不是一个选项。
其他更多信息
- 使单元格不透明会导致单元格只布置一次!奇怪!
最后,很抱歉我不能分享任何实际代码,因为它不是一个测试项目,而且实现的复杂性使得任何代码共享都是徒劳的,除非作为一个整体来理解。
感谢您的宝贵时间。
如果有人遇到同样的问题:
如果您正在计算单元格高度及其元素,并且您依赖 NSIndexPath
来查询任何数据或条件,请始终检查您的索引路径是否有效(而不是 nil
)。 return 索引路径(例如 -(NSIndexPath *)indexPathForCell:..
等)的大多数 UITableView
方法可能 return nil
值,并且会让你陷入调试视图的螺旋.
在我的例子中,我有一个方法来确定我的单元格是否应该有一个 header,为此我检查了它是第一个单元格还是自上一个单元格以来条件发生了变化。问题是 indexPath.row == 0
是真的,即使索引路径实际上是 nil
(这是 Objective-C 中的概念问题,其中 nil
是 0)。所以有那么一小会儿我的细胞会认为它有 header!
我觉得不检查 nil
索引路径有点愚蠢,但我认为分享它可能有一天会对某人有所帮助。
我在使用 reloadRowsAtIndexPath 时也遇到了 UITableViewCell 闪烁的问题,所以我所做的是 -
[UIView setAnimationsEnabled:NO];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
[UIView setAnimationsEnabled:YES];
上面的代码片段在重新加载单元格时不会在单元格上显示动画。
我在 swift 中使用它,它减少了闪烁
let visibleIndexs = self.ContentTableview.indexPathsForVisibleRows! as NSArray
print(visibleIndexs)
for indx in visibleIndexs {
if self.imgDownloadedIndexs!.containsObject(indx) {
UIView.setAnimationsEnabled(false)
self.ContentTableview.beginUpdates()
self.ContentTableview.reloadRowsAtIndexPaths([indx as! NSIndexPath], withRowAnimation:.None)
self.ContentTableview.endUpdates()
UIView.setAnimationsEnabled(true)
self.imgDownloadedIndexs?.removeObject(indx)
}
是的,您可以使用 performWithoutAnimation
(Swift 版本)
UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none)
}
删除 rowHeightAtIndexPath 方法将解决此问题。确保您已为情节提要中的 table 单元格设置了一些固定高度。
tableView 自定义单元格不可点击且闪烁。这是因为细胞动画。添加以下代码后,单元格可以点击并且工作正常。 这种情况正常发生,也可能发生在运行 UITestCase.
时func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none)
}
return cell
}