我使用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方法。
答案 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.contentOffset
,scrollView.contentSize
,tableView.indexPathsForVisibleRows
等来检查表的状态......
答案 5 :(得分:0)
实际上,prefetchingEnabled
上有UICollectionView
属性可以满足您的需求。
摘要
表示是否启用单元和数据预取。声明
@property(nonatomic, getter=isPrefetchingEnabled) BOOL prefetchingEnabled;
讨论
当为“是”时,集合视图将在其出现之前请求单元格 将显示,将渲染分布在多个布局上 通过。如果为“否”,则请求单元,因为它们需要 显示,通常在同一渲染中请求多个单元格 循环。将此属性设置为NO也会禁用数据预取。的 此属性的默认值为YES。注意当预取是 在上启用了collectionView:cellForItemAtIndexPath:方法 集合视图委托在单元格何时被调用之前被调用 需要。为避免视觉外观不一致,请使用 collectionView:willDisplayCell:forItemAtIndexPath:委托方法 更新单元格以反映视觉状态,例如选择。
答案 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。打开尺寸检查器,然后在“表格视图”部分中取消选中“估算”行旁边的复选框。