总结 在顶部插入新单元格时,我的具有动态单元格高度的 UITableView 会随机滚动。
详细说明 作为 UITableViewController 的一部分,为了避免在我触发 reloadData() 和滚动时滚动不准确,我有以下基于此堆栈溢出的工作实现 answer :
var cellHeightsDictionary: [IndexPath: CGFloat] = [:]
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeightsDictionary[indexPath] = cell.frame.size.height
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = cellHeightsDictionary[indexPath] {
return height
}
return UITableView.automaticDimension
}
除了在数据源的顶部添加新数据并触发 reloadData() 之外,这工作得很好。这样做时,我还没有找到一个合适的实现来防止表格随机滚动……这就是我要解决的问题。
我尝试过的
我尝试使用更新前后的 contentSize 的差异,然后更新滚动位置。不幸的是,根据我在 Apple 文档中阅读的内容,似乎在使用动态单元格时,contentSize 不能用于此目的,并且对我不起作用。不过作为引用,这里是我的一个实现。
UIView.performWithoutAnimation { //检测单元格相对于导航栏的确切位置 让 navBar = navigationController?.navigationBar 让 cellRectInTable = tableView.rectForRow(位于:IndexPath(行:topArticle + countOfAddedItems,部分:0)) 让 positionVsNavBar = tableView.convert(cellRectInTable.origin, to: navBar) 让 positionVsTop = tableView.convert(cellRectInTable.origin, to: tableView.superview) 让 offsetOfCell = positionVsTop.y - positionVsNavBar.y tableView.reloadData() tableView.scrollToRow(位于:IndexPath(行:topArticle + countOfAddedItems,部分:0),位于:.top,动画:false) tableView.contentOffset.y = tableView.contentOffset.y + offsetOfCell }
我尝试在添加之前设置 tableView.estimatedRowHeight = 0、tableView.estimatedSectionHeaderHeight = 0 和 tableView.estimatedSectionFooterHeight = 0,但似乎没有任何影响。
似乎最有效的方法是当我从 cellHeightsDictionary 获取单元格的高度并根据添加的数量对它们求和时。这有时会完美无缺地工作,但有时却不会。此外,当添加大量行时,它可能会崩溃,因为它没有在 cellHeightsDictionary 中找到值。我尝试了多种变体,但没有成功。同样重要的是,我不确定为什么这给了我最好的结果,所以我可能会遗漏一些明显的东西。我感觉最后一个实现中的某个地方就是答案,但我一直无法找到它。
var 迭代器计数器 = 0
var heightCum = CGFloat(整数文字: 0)
而 iteratorCounter < countOfAddedItems {
heightCum = heightCum + cellHeightsDictionary[IndexPath(row: iteratorCounter, section: 0)]!
迭代器计数器 = 迭代器计数器 + 1
}UIView.performWithoutAnimation { tableView.reloadData() tableView.layoutIfNeeded() tableView.contentOffset.y = tableView.contentOffset.y + heightCum }
我已经尝试了我能想到的一切,并在我想到的所有地方进行了搜索,但没有成功。任何帮助表示赞赏
感谢一百万!
最佳答案
作为最后的手段,您可以将 TableView 嵌入到新的 ScrollView 中并关闭 TableView 的滚动。您可以完全控制滚动行为(尽管都是以编程方式)。
在这种情况下,我们必须添加一个布局约束对应于表格 View 的高度,以及这个约束的导出。
如果我们的单元格 View 有适当的布局,我们可以使用 systemLayoutSizeFittingSize
方法计算准确的单元格高度。如果单元格有多个标签(例如动态内容),请尝试使用固定宽度进行计算(在单元格中添加显式宽度限制)。
有了这个,我们可以重新加载 TableView ,如下所示:
1)向数据源插入数据
2) 重新计算内容高度
3)修改高度约束常量
4) 调用layoutIfNeeded
5) 重新加载 TableView
6) 适当移动 ScrollView 内容偏移=> setContentOffset(_ contentOffset: CGPoint, animated: Bool)
关于swift - TableView w。重新加载新数据时动态高度滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53830667/