You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TableView自定义分页:willDisplayCell触发非可视单元格问题求解

解决UITableView分页时willDisplay提前触发的问题

我完全懂你遇到的这个痛点——UITableView为了让滚动更流畅,会提前预加载一些不在当前屏幕内的单元格,结果就是willDisplay甚至cellForRowAt会在最后一个单元格还没进入用户视野时就触发加载请求,完全不符合我们想要的"滚动到底部才加载"的分页逻辑。下面给你两个实用的解决方案,附带代码调整:

方案一:优化willDisplay触发逻辑,确保单元格真正可见

核心思路是在原有判断基础上,新增单元格是否处于屏幕可视范围的校验,同时加上加载状态锁,彻底避免重复请求。

首先添加一个加载状态标记:

private var isLoading = false // 标记是否正在加载数据,防止重复请求

然后修改你的willDisplay方法:

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    // 正在加载时直接返回,避免重复触发请求
    guard !isLoading else { return }
    
    // 先判断是否是最后一行,且还有未加载的数据
    guard indexPath.row == orders.count - 1, totalItems > orders.count else { return }
    
    // 校验当前单元格是否真的进入了屏幕可视区域
    let cellFrame = tableView.rectForRow(at: indexPath)
    let visibleFrame = CGRect(origin: tableView.contentOffset, size: tableView.bounds.size)
    guard cellFrame.intersects(visibleFrame) else { return }
    
    // 满足所有条件,触发下一页加载
    fetchNextPage()
}

接着更新fetchNextPage和addOrders方法,维护加载状态:

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

func addOrders(_ orders: [OrderView]) {
    self.orders.append(contentsOf: orders)
    reloadOrders()
    // 数据加载完成后,重置加载状态
    isLoading = false
}

方案二:改用scrollViewDidScroll监听滚动,自定义加载时机

这种方式更灵活,无需依赖单元格的预加载逻辑,而是主动监听滚动位置,当用户滚动到距离底部一定距离时触发加载(比如提前100pt开始加载,让用户几乎感知不到等待)。

同样保留isLoading状态锁,实现UIScrollViewDelegate的方法:

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    // 过滤掉加载中、没有更多数据的情况
    guard !isLoading, totalItems > orders.count else { return }
    
    let contentOffsetY = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height
    let tableViewHeight = scrollView.bounds.size.height
    let triggerThreshold: CGFloat = 100 // 提前加载的距离,可根据需求调整
    
    // 计算是否滚动到了触发加载的位置
    if contentOffsetY > contentHeight - tableViewHeight - triggerThreshold {
        fetchNextPage()
    }
}

关键注意事项

  • 加载状态锁是核心:不管用哪种方案,isLoading都能有效防止滚动过程中多次触发请求,避免重复数据或服务器报错。
  • 保证totalItems的准确性:这个值必须是服务器返回的真实总数据条数,否则会出现无限加载或提前停止加载的问题。
  • 处理contentInset:如果你的tableView设置了contentInset(比如底部有安全区),计算滚动位置时要把contentInset.bottom纳入考量,避免触发时机不准确。

内容的提问来源于stack exchange,提问作者atereshkov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:34:50