iOS UITableView reloadData()之后setContentOffset无法回到最顶端

需求:

点击切换leftTableView中的主题时,刷新rightTableView中的数据源,并使rightTableView滑动到顶部。

操作:

通常设置tableView的内容偏移量有3种方法:

1. tableView.setContentOffset(CGPoint(x: 0.0, y: 0.0), animated: false)
2. tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
3. tableView.scrollRectToVisible(CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0), animated: false)

我是直接使用的方法1.

// 点击切换时,执行
rightTableView.mj_header.endRefreshing()
rightTableView.reloadData()
rightTableView.setContentOffset(CGPoint(x: 0.0, y: 0.0), animated: false)
问题:

切换后,数据源刷新了,但是rightTableView并未滑动到最顶部,如图。


iOS UITableView reloadData()之后setContentOffset无法回到最顶端_第1张图片
tableview scroll to top error.gif
原因:

通过打印发现rightTableView执行完操作后的contentOffset并不为(0.0, 0.0),说明reloadData()后立刻执行setContentOffset的操作无效。

tableView.reloadData() 并不会等待tableview更新结束后才执行后续代码,而是立即执行后续代码,然后异步地去计算scrollView的高度,获取cell等等。如果表中的数据非常大,在一个run loop周期没执行完,这时就显示tableView视图数据的操作就会出问题了。

如果在reloadData后需要立即获取tableview的cell、高度,或者需要滚动tableview。如果直接在reloadData后执行代码是有可能出问题的,比如indexPath为nil等等异常情况。

解决方法:

使用上述的方法2.即可解决,如下

rightTableView.reloadData()
rightTableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)

** (注意:试验发现 使用方法3. tableView.scrollRectToVisible也不行)**

iOS UITableView reloadData()之后setContentOffset无法回到最顶端_第2张图片
tableview scroll to top right.gif

补充:
这篇文章中说 想要程序延迟到reloadData结束再操作,可以通过在reloadData()后先执行layoutIfNeeded()、 或者是把后续代码放在 DispatchQueue.main.async {}中执行, 经测试发现这两种做法都不太可靠,有时仍不准确。

另:
页面首次出现时,默认选中leftTableView第一个,并在rightTableView中刷新数据的方法:

// 我是统一在UITableViewDelegate的didSelectRowAt中执行刷新操作的
leftTableView.selectRow(at: IndexPath(row: 0, section: 0), animated: false, scrollPosition: .none)
tableView(leftTableView, didSelectRowAt: IndexPath(row: 0, section: 0))

你可能感兴趣的:(iOS UITableView reloadData()之后setContentOffset无法回到最顶端)