Objective-C聊天UITableView双向分页向下加载偏移自动跳转问题求解
双向分页加载头部数据后tableView跳转死循环解决方案
核心原因
你向消息数组头部插入历史消息后调用reloadData,tableView会默认重置滚动位置到最顶部,直接触发你设置的offset.y < 10的分页判断,形成死循环。
解决方案
方案1:使用局部插入代替全局reload(推荐,无需手动计算偏移)
不需要手动计算偏移,系统会自动保留当前滚动位置,实现无感知加载:
- 先往
_messagesArray头部插入你拿到的分页数据,记录插入的条数addedCount - 生成对应要插入的indexPath数组,调用insertRows方法更新tableView:
if (scrollDirectionDown) { _paginationMessagesArray = [[[_paginationMessagesArray reverseObjectEnumerator] allObjects] mutableCopy]; NSInteger addedCount = _paginationMessagesArray.count; // 构造插入的indexPath数组 NSMutableArray *insertIndexPaths = [NSMutableArray array]; for (NSInteger i = 0; i < addedCount; i++) { [insertIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; } // 更新数据源 [_paginationMessagesArray addObjectsFromArray:_messagesArray]; _messagesArray = _paginationMessagesArray; // 局部更新tableView,不要调用全局reloadData [_tableView beginUpdates]; [_tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationNone]; [_tableView endUpdates]; }
方案2:手动计算偏移(适合必须全局reloadData的场景)
如果你的业务必须调用reloadData,可以通过记录原可见cell位置的方式,reload后还原滚动位置:
- 插入数据前先记录当前第一个可见cell的位置和偏移
// 插入新数据前执行 NSIndexPath *originalFirstIndexPath = [_tableView indexPathsForVisibleRows].firstObject; CGRect originalFirstCellRect = [_tableView rectForRowAtIndexPath:originalFirstIndexPath]; CGFloat offsetFromTop = originalFirstCellRect.origin.y - _tableView.contentOffset.y;
- 插入新数据并reload后,还原偏移
NSInteger addedCount = _paginationMessagesArray.count; NSInteger newTargetRow = originalFirstIndexPath.row + addedCount; NSIndexPath *newTargetIndexPath = [NSIndexPath indexPathForRow:newTargetRow inSection:0]; [_tableView reloadData]; [_tableView layoutIfNeeded]; // 强制立刻布局,确保cell高度计算准确 CGRect newTargetRect = [_tableView rectForRowAtIndexPath:newTargetIndexPath]; CGFloat newOffsetY = newTargetRect.origin.y - offsetFromTop; [_tableView setContentOffset:CGPointMake(0, newOffsetY) animated:NO];
辅助优化点
- 你在
scrollViewDidScroll中触发loadMessages时,必须立刻将isLoadingMessages设为YES,不要等到接口返回才修改状态,避免请求过程中重复触发加载 - 顶部分页触发条件可以从
offset.y < 10调整为距离顶部还有1-2个cell高度时就触发,加载更顺滑,配合isLoadingMessages状态不会重复请求
内容的提问来源于stack exchange,提问作者Sergey Udalov
相关产品推荐
相关产品推荐

