调用 reloadData 后 UITableView 动态单元格高度滚动到顶部

Posted

技术标签:

【中文标题】调用 reloadData 后 UITableView 动态单元格高度滚动到顶部【英文标题】:UITableView dynamic cell height scroll to top after calling reloadData 【发布时间】:2017-05-22 11:53:20 【问题描述】:

我的 tableView 中有动态单元格高度

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100

我想和 whatsapp 应用程序(分页)一样,我想加载 25 x 25 行,所以当用户在顶部滚动时,我想加载新数据但我想保持相同的滚动位置,这就是我做了

func scrollViewDidScroll(_ scrollView: UIScrollView) 
    if isMore && scrollView.contentOffset.y == 0 
         loadMore() // function that add new data in my model
         self.tableView.reloadData()
    
 

我遇到的问题是在我到达我的 tableview 顶部后它调用 reloadData 但 tableView 滚动到 UP

我测试了其他一些类似的解决方案:

var cellHeights: [IndexPath : CGFloat] = [:]

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
    cellHeights[indexPath] = cell.frame.size.height


func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat 
    guard let height = cellHeights[indexPath] else  return 70.0 
    return height
   

还是不行

【问题讨论】:

默认情况下,表格视图上的.reloadData() 不会更改表格的滚动位置。也许您的loadMore() 中的其他内容或其他功能正在更改表格视图属性? 是的,因为我使用动态单元格高度 UITableViewAutomaticDimension 嗯...你说“当用户在顶部滚动时,我想加载新数据” ...所以你想在零行上方添加新行? 您的意思是像在 Whatsapp 中一样,当您在聊天中向上滚动并加载较旧的消息时? 是的,这就是我想要的 【参考方案1】:

如果您正在重新加载表格以添加更多数据,则在重新加载后调用下面的函数以保留滚动位置。

tableview.scrollToRow(at: indexPath, at: .middle, animated: true)

这里的indexPath是reload前最后一个cell的indexPath。

【讨论】:

这个函数的位置不完全相同 你可以试试改UITableViewScrollPosition吗? 我如何得到这个职位? UITableViewScrollPosition 是一个枚举。而不是 .middle 您可以更改为 .bottom 或 .top 我做到了,但它在更新之前并没有保持滚动的确切位置,请检查 whatsapp 在加载新数据时滚动,它不会停止滚动【参考方案2】:

tableView:cellForRowAt 中,当您检测到indexPath 接近最后一个元素时(当indexPath.row 接近yourArray.count 时),查询更多项目。当您拥有它们时,将它们添加到您的数据源(数组或其他任何东西,您可以在其中拥有表中表示的所有对象)并重新加载表视图。表格视图应该显示新项目,用户可以继续滚动而无需做任何特别的事情。

您不应等到最后一个单元格调用tableView:cellForRowAt,因为如果您需要调用服务器以获取更多项目,用户将不得不等待。 Whatsapp 的滚动速度很快,因为它们会在您滚动到最后一个元素之前很好地下载项目(前一段时间它确实在最后停止,但现在他们可能更早地获取新项目)。

请记住,25 个项目可能太少,如果网络速度较慢,用户可能会在显示更多项目之前滚动浏览您拥有的项目并且必须等待,这不是一个好的用户体验。模拟慢速网络连接,看看 25 个项目是否足以在您的应用与服务器联系时滚动浏览(取决于网络速度、请求和响应大小、服务器响应您请求的速度等)。

【讨论】:

我所做的只是在 indexPath.row == 0 上进行测试,因为我想像 whatsapp 一样在顶部而不是底部加载数据,但问题是因为我有动态单元格高度“UITableViewAutomaticDimension”,当我调用tableview的reloadData,滚动的位置总是在row = 0,就像它重绘表格一样【参考方案3】:

我在消息应用程序中遇到了同样的问题。以下是我的解决方法:

    为数据源数组中的每个消息分配一个唯一的messageId

    cellForRow: 中,我将第一行的messageId 保存在一个名为messageIdFirst 的变量中。

    if(indexPath.row == 0)
        messageIdFirst = message.id!
    
    

    loadMore() 方法中,我检查当前 indexpath 行在现在更新的数据源数组中具有相同的 messageId

    if(message.id == messageIdFirst)
        previousTopIndexPath = i
    
    

    ,其中 i 是数据源数组中具有相同 messageId.

    的索引

    现在,我像这样滚动到 previousTopIndexPath

    tableview.scrollToRow(at: previousTopIndexPath, at: .middle, animated: true)

注意 1:由于这在 UITableView 中无法有效工作,我最终将 UICollectionView 与相同的解决方案一起使用。

注意 2:虽然这确实工作顺利,但我知道必须有一种更清洁的方法来做到这一点。

【讨论】:

以上是关于调用 reloadData 后 UITableView 动态单元格高度滚动到顶部的主要内容,如果未能解决你的问题,请参考以下文章

在 UICollectionView 上调用 reloadData 后 contentSize 未更新

在主线程上调用 tableView.reloadData 后 UITableView 不刷新

升级到 iPhone OS 4 后,我的 TableView 在调用 reloadData 后滚动到顶部

UICollectionView 在调用 reloadData 时不会立即更新,而是在 30-60 秒后随机更新

调用 reloadData 后 UITableView 动态单元格高度滚动到顶部

在 swift uiTableView 中调用 reloadData() 后,旧项目剩余,新项目未显示