滚动/分页时,UITableView无法正确处理contentOffset

时间:2017-09-18 18:57:52

标签: ios uitableview uiscrollview

我有非常大量数据的表格视图。 出于性能原因,无法一次性加载。 更多,有时应该加载数组的随机位置,因此增量分页不是一个好选择。

这些要求的当前解决方案是在数据阵列上滑动窗口。当用户滚动时,我从一端添加单元格并从另一端移除。我使用滚动位置(通过查看屏幕上的单元格)来确定是否有时间加载新数据。

通常,当您调用tableView.deleteRows(at:with:)并从表的开头删除单元格时,tableView会调整其contentOffset属性,以便用户仍然可以看到与操作前相同的单元格。

但是,当tableView在滚动后减速时,其contentOffset在更新时不会调整,这会导致反复加载新页面直到减速完成。然后,在减速后的第一次更新中,contentOffset由tableView修复并且加载停止。

向后滚动并使用tableView.insertRows(at:with:)在表格的开头添加值时会发生同样的事情。

如何让UITableView正确调整其contentOffset?

还有其他方法可以克服这个错误 - 保持在数据数组中间加载任意部分并从中滚动的能力吗?

我做了一个小项目来说明这个错误:

https://github.com/wsb9/TableViewExample

2 个答案:

答案 0 :(得分:2)

从您的示例项目中,我可以理解以下内容,

  • 有一件事是你希望通过一次加载少量单元格来提高表格视图的性能
  • 您的第二个问题是有时您希望使用随机放置在数据源数组中的数据加载表视图

我检查了您的代码,您已经非常有趣地实施了sliding-window over data-source model。由于您一直试图通过删除和读取单元格来有效地tableview而导致的问题。

实际上,出列单元格应该重用已经在内存中的单元格。请看一下苹果文档,

  

出于性能原因,通常应该使用表视图的数据源   在将单元格分配给其中的行时,重用UITableViewCell对象   tableView(_:cellForRowAt :)方法。表视图维护队列或   数据源已标记的UITableViewCell对象的列表   重用。在被要求时,从您的数据源对象中调用此方法   为表视图提供一个新单元格。这种方法出了问题   现有单元格(如果有)或使用该类创建新单元格   或您之前注册的nib文件。如果没有可用的单元格   重用并且您没有注册类或nib文件,这种方法   返回nil。

好消息是,我删除了行删除和读取机制后,sliding-window over data-source model工作正常。这是您的工作代码,

https://drive.google.com/file/d/0B2y_JJbzjRA6dDR3QzRMUzExSGs/view?usp=sharing

答案 1 :(得分:1)

从您的示例项目中,我可以理解您是否正在尝试通过窗口内容概念实现无限滚动,以便您始终可以拥有固定数量的行(索引路径,例如100),以便在窗口向下/向上滚动时 - 表视图相应地从顶部/底部删除indexPaths。 即使你有更多的数据源项,你总是可以拥有indexPaths的tableViews 100

基本上你在这里处理两个问题:

  1. ContentOffset

  2. 动态高度

  3. 假设我们有高度固定(44)并且表没有反转。 要实现无限滚动窗口,您必须执行以下操作:

    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
            let bottom: CGFloat = scrollView.contentSize.height - scrollView.frame.size.height
            let buffer: CGFloat = 3 * 44
            let scrollPosition = scrollView.contentOffset.y
    
            if (scrollPosition > bottom - buffer) {
                dataSource.expose(dataSource.exposedRange.shift(by: 25))
                self.tableView.contentOffset.y -= self.dataSource.deltaHeightToRemove
            }
        }
    
    • 确定滚动下降时需要保留多少高度缓冲区。此高度缓冲区是您决定在数据源中插入更多项目(25)的高度。
    • 此时您必须从顶部
    • 中删除项目
    • 当您从顶部删除项目时,您基本上是在告诉scrollView将内容偏移减少相同的高度。
    • 这样每次都会确定总内容大小

      希望它会有所帮助。

      修改: - 这是修改后的代码,实际上在底部进行无限滚动 具有动态单元格高度的表视图。这不会使行数增加超过100.但仍会在滑动窗口中加载数据。 link