UITableView分页加载时Activity Indicator异常问题求助
解决UITableView滚动到最后Cell才加载数据并正确显示Activity Indicator的问题
看起来你遇到的核心问题是数据加载太快(因为直接操作本地数组),导致滚动还没到最后一行就加载完了,同时Activity Indicator一直显示。另外你的moreData()里的增量逻辑也有点问题(总数据只有11条,初始6条,剩余5条,但你每次加10,会导致越界判断)。我来帮你调整代码,实现滚动到最后一个Cell时才开始加载动画和数据:
第一步:添加加载状态标记,防止重复触发
首先在类里添加一个布尔变量,用来标记当前是否正在加载数据,避免滚动时多次触发加载逻辑:
class searchRecordsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,favouriteButtonTableViewCellDelegate { var y = 6 var m = 12 @IBOutlet weak var tableView : UITableView! var RESULT : [NSDictionary] = [] var myProperty = [property]() var myPropertyCopy = [property]() // 添加这个标记,防止重复加载 var isLoading = false // 新增 // ... 其他代码 }
第二步:修正willDisplay的判断逻辑
在willDisplay里,先判断是否正在加载,再判断是否到了最后一行,避免重复触发:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // 先判断是否还有数据未加载,且当前没有在加载 guard myPropertyCopy.count < myProperty.count, !isLoading else { // 如果没有数据了或者正在加载,隐藏footer self.tableView.tableFooterView?.isHidden = true return } let lastRowIndex = myPropertyCopy.count - 1 if indexPath.row == lastRowIndex { // 显示Activity Indicator let spinner = UIActivityIndicatorView(style: .gray) spinner.startAnimating() spinner.frame = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 44) self.tableView.tableFooterView = spinner self.tableView.tableFooterView?.isHidden = false // 开始加载更多数据 moreData() } }
第三步:修改moreData()方法,模拟网络请求延迟并修正增量逻辑
因为你现在是直接操作本地数组,加载速度极快,所以我们需要模拟网络请求的延迟(真实场景中是异步请求PHP接口),同时修正y和m的增量,避免超出总数据长度:
func moreData(){ // 标记为正在加载 isLoading = true // 模拟网络请求延迟(真实场景中这里替换成Alamofire请求PHP接口的代码) DispatchQueue.global().asyncAfter(deadline: .now() + 1.5) { [weak self] in guard let self = self else { return } // 计算本次要加载的数量:剩余数据 = 总数据数 - 当前已加载数 let remainingCount = self.myProperty.count - self.myPropertyCopy.count // 最多加载5条(你可以改成你想要的每页数量) let loadCount = min(remainingCount, 5) // 从y开始加载loadCount条 for i in self.y ..< self.y + loadCount { if self.myProperty.indices.contains(i) { self.myPropertyCopy.append(self.myProperty[i]) } } // 更新y的位置 self.y += loadCount // 回到主线程刷新UI DispatchQueue.main.async { self.tableView.reloadData() // 加载完成,标记为未加载状态 self.isLoading = false // 如果没有更多数据了,隐藏footer if self.myPropertyCopy.count == self.myProperty.count { self.tableView.tableFooterView?.isHidden = true } } } }
第四步:修正viewWillAppear里的初始数据加载(可选优化)
你原来的初始加载循环可以简化一下,避免越界:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationItem.title = "Results" self.navigationController?.navigationBar.tintColor = UIColor.black // 先清空数组,避免重复添加(如果viewWillAppear多次触发的话) myProperty.removeAll() myPropertyCopy.removeAll() y = 6 // 重置初始位置 for item in RESULT { let propertyInfo = property( property_Id: String(item["propertyId"]! as! Int), propertyTitle: item["propertyTitle"]! as! String, imageURL: item["imagePath"]! as! String, user_Id: String(item["userId"]! as! Int), area: item["area"]! as! String, bed: item["bed"]! as! String, unit: item["unit"]! as! String, bath: item["bath"]! as! String, price: item["price"]! as! String ) myProperty.append(propertyInfo) } // 初始加载前6条 let initialLoadCount = min(6, myProperty.count) for i in 0 ..< initialLoadCount { myPropertyCopy.append(myProperty[i]) } // 刷新表格 tableView.reloadData() }
解释改动点:
isLoading标记:防止用户快速滚动时多次触发加载逻辑,避免重复添加数据- 模拟网络延迟:用
DispatchQueue.global().asyncAfter模拟真实网络请求的耗时,这样Activity Indicator会有足够的时间显示出来 - 修正加载数量计算:不再固定加10,而是根据剩余数据量来决定加载多少条,避免逻辑错误
- 主线程刷新UI:所有UI操作必须在主线程执行,所以刷新表格和更新状态要回到主线程
- 隐藏footer的逻辑:当没有更多数据时,自动隐藏Activity Indicator
这样修改后,你滚动到最后一个Cell时,Activity Indicator才会开始动画,等待1.5秒后加载剩余的5条数据,加载完成后Indicator会隐藏,完美符合你的需求。
内容的提问来源于stack exchange,提问作者Ahtazaz
相关产品推荐
相关产品推荐

