TableView willDisplayCell调用不在屏幕上的单元格(tableView分页)

时间:2018-01-07 11:14:07

标签: ios swift uitableview pagination

我使用willDisplayCell(或cellForRowAt)使用the idea of custom TableView pagination并从服务器更新。

问题是willDisplay甚至会调用不在屏幕上的单元格。

如果用户滚动到最后一个单元格,我该如何处理此行为并更改流程以更新单元格?

private func isLoadingIndexPath(_ indexPath: IndexPath) -> Bool {
    return indexPath.row == self.orders.count - 1
}

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // fetch new data if user scroll to the last cell
    guard isLoadingIndexPath(indexPath) else { return }
    if self.totalItems > orders.count {
        fetchNextPage()
    }
}

private func fetchNextPage() {
    self.currentPage += 1
    self.delegate?.didReachLastCell(page: currentPage)
}

didReachLastCell调用addOrders:

func addOrders(_ orders: [OrderView]) {
    self.orders.append(contentsOf: orders)
    reloadOrders()
}

fileprivate func reloadOrders() {
    self.tableView.reloadData()
}

注意:同样的问题也可以重现cellForRowAt方法。

8 个答案:

答案 0 :(得分:4)

在使用UITableView.automaticDimension作为像元高度时遇到了这个问题。我为estimatedRowHeight属性使用了更高的值来解决了这个问题。

类似这样的东西:

tableView.estimatedRowHeight = 1000

现在willDisplay仅在可见行中被调用。

答案 1 :(得分:3)

正如@iWheeBuy所说,willDisplayCell不会说该单元格在屏幕上,因此您可以通过检入tableView.visibleCells来实现。

但是,即使在滚动时调用此函数并将其显示在屏幕上,tableView.visibleCells.contains(cell)也会为假。

对我有用的一种方法是延迟,因此完整代码为:(SWIFT 4)

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            if tableView.visibleCells.contains(cell) {
                // load more data
            }
        }
    }

答案 2 :(得分:2)

tableView(_:willDisplay:forRowAt :): 调用此方法时,无论所有单元格是否可见,都将首次返回所有单元格。 因此,如果要在此方法中实现分页逻辑,则必须首先检查可见单元格。 即

    if let visibleRows = tableView.indexPathsForVisibleRows , indexPath == visibleRows.last {
        guard isLoadingIndexPath(indexPath) else { return }
        if self.totalItems > orders.count {
            fetchNextPage()
        }
    }
      

答案 3 :(得分:0)

实现这3个scrollViewDelegate方法并使用固定高度的单元格num和当前的scrollOffset来知道它是否是最后一个单元格

func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {

}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

}
//Pagination
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

 }

答案 4 :(得分:0)

有关tableView(_:willDisplay:forRowAt:)的文档:

  

表视图在使用之前将此消息发送到其委托   单元格绘制一行,从而允许委托自定义   显示之前的单元格对象。这个方法给代表一个   有可能覆盖表格前面设置的基于状态的属性   视图,例如选择和背景颜色。代表之后   返回时,表视图仅设置alpha和frame属性,以及   然后只有当它们滑入或滑出时动画行。

此描述并未提及仅针对屏幕上的单元格调用该方法。

您可以将您的分页逻辑放到其他方法/方法中。例如:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    //
}

然后使用scrollView.contentOffsetscrollView.contentSizetableView.indexPathsForVisibleRows等来检查表的状态......

答案 5 :(得分:0)

实际上,prefetchingEnabled上有UICollectionView属性可以满足您的需求。

  • prefetchingEnabled

摘要

表示是否启用单元和数据预取。声明

@property(nonatomic, getter=isPrefetchingEnabled) BOOL prefetchingEnabled;

讨论

当为“是”时,集合视图将在其出现之前请求单元格 将显示,将渲染分布在多个布局上 通过。如果为“否”,则请求单元,因为它们需要 显示,通常在同一渲染中请求多个单元格 循环。将此属性设置为NO也会禁用数据预取。的 此属性的默认值为YES。注意当预取是 在上启用了collectionView:cellForItemAtIndexPath:方法 集合视图委托在单元格何时被调用之前被调用 需要。为避免视觉外观不一致,请使用 collectionView:willDisplayCell:forItemAtIndexPath:委托方法 更新单元格以反映视觉状态,例如选择。

来源: Apple Documentation

答案 6 :(得分:0)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
   if tableView.visibleCells.contains(cell) {
      if (indexPath.row == self.arrProduct.count - 1){
                    if self.arrProduct.count > 0 {
                        if(self.arrProduct.count % self.RECORD_SET_LIMIT == 0 && self.isLoadMore) {
                            self.currentPage = self.currentPage + 1
                            print(self.currentPage)
                            self.perform(#selector(self.serviceGetProductByStatus), with: nil, afterDelay: 0.1)
                        }
                    }
                }
            }
        }

答案 7 :(得分:0)

在您的界面生成器中,选择UITableView。打开尺寸检查器,然后在“表格视图”部分中取消选中“估算”行旁边的复选框。