UITableView - reloadRows 方法创建奇怪的滚动错误

Posted

技术标签:

【中文标题】UITableView - reloadRows 方法创建奇怪的滚动错误【英文标题】:UITableView - reloadRows method creating weired scrolling bug 【发布时间】:2019-07-12 10:03:12 【问题描述】:

我在我的一个应用程序中使用UITableView。在 tableview 的行内,我有水平滚动 UICollectionView。每当用户双击集合视图的单元格时,它会将事件发送回视图控制器以更新数据源。更新数据源后,我正在使用:tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none) 重新加载该特定行但我遇到了奇怪的滚动错误。

我想重新加载 tableview 的行及其内容,即 collectionview 的内容,没有任何动画或滚动问题。

我尝试了以下解决方案来避免这种情况,但没有运气:(

UIView.performWithoutAnimation 
    self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)

我什至试图记住 tableview 和 collectionview 的内容偏移,但闪烁仍然存在。如果您遇到此类问题,请指导我

【问题讨论】:

向我们展示“奇怪”的滚动错误 它从顶部滚动并返回到上一个位置或之前可见的行。 如果您想更新该行,请不要重新加载它 - 您知道该单元格可能是可见的,因为用户只是与它进行了交互。使用cellForRow(at:) 检索单元格并更新它。如果您在尝试检索单元格时收到nil,请继续前进,因为该单元格不在屏幕上,下次出现时会更新 你不认为这样的实现会有出队问题吗? 不,单元格要么在屏幕上,在这种情况下你可以直接更新它,或者它不在屏幕上,在这种情况下你不需要做任何事情 - 注意,我在说关于调用UIITableView函数cellForRow(at:),而不是你已经实现的数据源方法。 【参考方案1】:

这是一个 UI 布局问题。当您重新加载一个单元格/部分时,它会重新计算其内容大小,因此如果您有一个动态大小的单元格,则特别是您的 tableView 内容大小。我会建议2个解决方案

解决方案一(Hacky):

保存当前视图 before-reload-state 表格视图的内容偏移,然后在没有动画的情况下在重新加载过程后滚动到它

解决方案二(更好):

直接更新您的数据源及其绑定单元格,而无需重新加载您的 UITableView(考虑改为更新您的 UICollectionView - 除非它被动态盗取,否则您需要为 UITableViewCell 高度设置动画)。

【讨论】:

很高兴! :)【参考方案2】:

在将图像放入单元格之前,如果可能,创建图像的缩略图,以便滚动。

【讨论】:

【参考方案3】:

我遇到了完全相同的问题。仅此一项就解决了问题:

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat 
    return self.tableView(tableView, heightForRowAt: indexPath)

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案4】:

尝试 tableView.reloadData() 或者您必须按升序重新排列 indexPath,然后重新加载特定的 indexPath。

【讨论】:

我不认为重新加载整个 tableview 是更好的主意 @JarvisTheAvenger 即使您调用tableView.reloadData() 整个表也不会重新加载。只有可见的单元格将被重新加载,因为其他单元格甚至不存在。 TableView 不会创建它们 @CerlinBoss tableView.reloadData() 将触发数据源,它将针对所有单元格数据进行迭代,但影响到唯一可见的单元格。 @KumarKL 我不这么认为。即使这样做,前端也没有任何意义,因为它只重新加载可见单元格.. @CerlinBoss 根据文档:Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload. The table view’s delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows,

以上是关于UITableView - reloadRows 方法创建奇怪的滚动错误的主要内容,如果未能解决你的问题,请参考以下文章

自定义 UITableViewCell 中的操作按钮调用的 UITableView reloadRows() 总是落后一步

Swift tableView.reloadRows 删除单元格

我可以在 micRowAve IndexPath... 中调用 reloadRows At IndexPath... 吗?

tableView.reloadRows(at:[indexPath],带有:.none)会像这样崩溃吗?

为啥调用 reloadRows 后,heightForRowAt 没有在数组中找到值?

Swift - saveContext()、tableView、scrollView 和 reloadRows 问题?