我有一个UITableView,其中包含一堆单元格。
如果用户单击第二个单元格,则第一个单元格应设置动画并显着扩展其高度,然后将所有其他单元格向下推,从而将用户的滚动位置保留在同一位置。当两个单元格都在屏幕上时,我的代码可以100%正确地工作。 UITableView的contentSize显着增长,并且contentOffset不变。
但是,如果用户向下滚动以使只有第二个单元格可见,那么当他们点击它时,第一个单元格会扩展到屏幕之外,并且对用户而言什么也没有发生。
UITableView的contentSize不变,contentOffset也不变。一旦用户稍微向上滚动并看到展开的单元格的底部,contentSize和contentOffset就会更新,以反映出第一个单元格确实更大(但从用户的角度看,没有任何变化)的事实
在扩展之前和之后调用heightForRowAtIndexPath
作为单元格的索引路径将返回期望值。
我的代码有很多事情要做,但是应该用来动画扩展的主要部分在这里:
UIView animateWithDuration:0.3
animations:^{
performSelectorOnMainThread(@selector(updateItemHeights:), withObject: nil, waitUntilDone: YES)
}
completion:^(BOOL finished){}]
以及updateItemHeights的实现:
beginUpdates
endUpdates
self.contentSize = sizeThatFits([contentSize.width, CGFLOAT_MAX])
iOS似乎试图通过允许上面的单元格扩展来使用户保持当前状态。
如何获得屏幕外的单元格以将其他单元格向下推?
答案 0 :(得分:1)
由于使用了表格视图出队系统,当一个单元格不可见时,它不会被加载。因此,如果表格视图在屏幕上不可见,则该表格视图不会设置动画效果。
我在这里看到2个选项:
滚动到动画单元格,然后再更新其高度
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let animatedIndexPath = ...
let visibleRows = tableView.indexPathsForVisibleRows ?? []
if visibleRows.contains(animatedIndexPath) {
self.tableView.reloadRows(at: [animatedIndexPath], with: .automatic)
} else {
UIView.animate(withDuration: 0.3, animations: {
self.tableView.scrollToRow(at: animatedIndexPath, at: .none, animated: false)
}) { _ in
self.tableView.reloadRows(at: [animatedIndexPath], with: .automatic)
}
}
}
在单元格更新后调整内容偏移量
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let animatedIndexPath = ...
let visibleRows = tableView.indexPathsForVisibleRows ?? []
if visibleRows.contains(animatedIndexPath) {
self.tableView.reloadRows(at: [animatedIndexPath], with: .automatic)
} else {
let offset = tableView.contentOffset
tableView.reloadData()
tableView.layoutIfNeeded() // forces the new offset computation
tableView.setContentOffset(offset, animated: true)
}
}
(由于表格视图动态高度计算,您可能会遇到一些问题,请将其tableView.estimatedRowHeight = 0
禁用)