当我插入新行时,UITableView 正在跳跃

Posted

技术标签:

【中文标题】当我插入新行时,UITableView 正在跳跃【英文标题】:UITableView is jumping when I insert new rows 【发布时间】:2018-03-14 18:33:27 【问题描述】:

我尝试了很多方法来解决这个问题,但我做不到。我的tableView 在加载更多数据后会跳转。我在willDisplay调用下载方法:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
    let lastObject = objects.count - 1
    if indexPath.row == lastObject 
        page = page + 1
        getObjects(page: page)
    

并在此处插入行:

func getObjects(page: Int) 
    RequestManager.sharedInstance.getObjects(page: page, success:  objects in
        DispatchQueue.main.async(execute: 
            self.objects = self.objects + objects
            self.tableView.beginUpdates()
            var indexPaths = [IndexPath]()
            for i in 0...objects.count - 1 
                indexPaths.append(IndexPath(row: i, section: 0))
            
            self.tableView.insertRows(at: indexPaths, with: .bottom)
            self.tableView.endUpdates()
        );
    )

那我做错了什么?为什么tableView插入新行后会跳转?

【问题讨论】:

【参考方案1】:

我刚刚找到了停止跳表视图的解决方案 在表视图中插入多行。我正面临这个问题 最近几天,所以我终于解决了这个问题。

我们只需要设置表格视图的内容偏移量,而 在表格视图中插入行。你只需要传递你的数组 IndexPath 休息你可以使用这个功能。

希望这个方法对你有帮助。

 func insertRows() 
    if #available(ios 11.0, *) 
        self.tableView.performBatchUpdates(
            self.tableView.setContentOffset(self.tableView.contentOffset, animated: false)
            self.tableView.insertRows(at: [IndexPath], with: .bottom)
        , completion: nil)
     else 
        // Fallback on earlier versions
        self.tableView.beginUpdates()
        self.tableView.setContentOffset(self.tableView.contentOffset, animated: false)
        self.tableView.insertRows(at: [IndexPath], with: .right)
        self.tableView.endUpdates()
    

【讨论】:

这个解决方案对我有用,现在我的 tableview 不再跳跃了! 太棒了,它也帮助了我【参考方案2】:

tableView 也有类似的问题。部分原因是我用beginUpdates() 和endUpdates() 决定的

self.tableView.beginUpdates()
self.tableView.endUpdates()

但这并没有解决问题。 对于 iOS 11,问题仍然存在。 我添加了一个包含所有单元格高度的数组,并在方法 tableView(_:heightForRowAt:)

中使用了这些数据
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return cellHeights[indexPath.row] ?? 0

同样添加这个方法tableView(_:estimatedHeightForRowAt:)

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat 
    return cellHeights[indexPath.row] ?? 0

在那之后,跳跃停止了。

【讨论】:

谢谢,现在跳得少了。但它仍然跳...我想要 Instagram 应用程序如何加载更多单元格... 我用 tableView(:estimatedHeightForRowAt:) 更新了我的答案。这很奇怪,但是 tableView (:estimatedHeightForRowAt :) 帮助我彻底摆脱了这个问题。 在哪里为 cellHeights 添加高度? 我在 CustomTable VieCell 类中进行高度计算。我总结了所有垂直约束,所有标签高度,视图高度...... 在文档中它说“使用 -performBatchUpdates:completion: 代替这些方法 (beginUpdates),这些方法将在未来的版本中弃用。”【参考方案3】:

首先,检查您的tableView(_:estimatedHeightForRowAt:) - 这永远不会准确,但单元格高度越可能以这个估计值结束,表格视图所做的工作就越少。

因此,如果您的表格视图中有 100 个单元格,那么您确定其中 50 个单元格最终的高度将为 75 - 这应该是估计值。

另外值得一提的是,表格视图可以向其代表询问确切单元格高度的次数没有限制。因此,如果您有一个包含 1000 行的表格视图,那么单元格之外的布局就会出现很大的性能问题(延迟以秒为单位) - 实施估计会大大减少这些调用。

您需要重新审视单元格设计的第二件事,是否有任何视图或控件的高度需要由表格视图计算?就像具有顶部和底部锚点的图像等价于其他视图,其高度从一个单元格到另一个单元格?

这些视图/控件的固定高度越多,表格视图就越容易布局其单元格。

我在两个表格视图中遇到了同样的问题,其中一个有一个可变高度的图像嵌入到堆栈视图中,我必须在其中实现估计。另一个没有固定大小的图像,我不需要执行估计来使其平滑滚动。 两个表视图都使用分页。

最后但同样重要的是,数组是结构。结构是值类型。所以也许你不想在数组中存储任何高度,看看你正在制作多少份? 计算tableView(_:heightForRowAt:) 内部的高度非常快速和高效,足以很好地计算出来。

【讨论】:

【参考方案4】:

因为您的循环从 0 运行到对象计数:

for i in 0...objects.count - 1 
     indexPaths.append(IndexPath(row: i, section: 0))

索引路径为第 0 行生成计数,直到对象计数。因此这些行被添加到表的顶部(即在第 0 行),因此导致表视图跳转,因为您在表视图的底部。

尝试将范围更改为:

 let rangeStart = self.objects.count
 let rangeEnd = rangeStart + (objects.count - 1)
 for i in rangeStart...rangeEnd 
     indexPaths.append(IndexPath(row: i, section: 0))
 

希望对你有帮助..!!!

【讨论】:

以上是关于当我插入新行时,UITableView 正在跳跃的主要内容,如果未能解决你的问题,请参考以下文章

如何在 NSMutableArray 中插入新行?

等待 UITableView 完成插入

动画将新行插入 UITableView 的新部分

为啥我的 UITableView 在插入或删除行时会“跳跃”?

UITableView - 通过点击现有单元格插入新行

UIRefreshControl 控件在插入新行后永远旋转