我在为 UITableView 中与其他行具有不同高度的行添加或删除动画时遇到问题。
以下 gif 演示了插入和删除默认高度 (44pts) 行和更大行 (100pts) 的问题。左边的是模拟器的屏幕录像(新单元格最终覆盖第五行是另一回事),右边的是它应该做什么的模型。
在我的例子中,我有一堆行,每行的高度为 60 磅。当点击单元格中的按钮时,“编辑”单元格将从下方滑出,将下方的单元格向下推。这个编辑单元格高 180pts。当我调用 insertRowsAtIndexPaths:withRowAnimation:
或 deleteRowsAtIndexPaths:withRowAnimation:
时,动画采用了错误的 60pts 高度,而不是应该的 180pts
这意味着在 UITableViewRowAnimationTop
的情况下,新单元格出现在距离它最终位置的 -60pts 处,并向下滑动到它的新位置;它应该做的大约三分之一的动画。同时,下面的行从其起始位置到向下 180pts 的动画效果非常流畅,完全符合预期。
有没有人想出一个实际的解决方案?有什么方法可以告诉新行动画的高度是多少?
下面是我用来隐藏和显示编辑行的代码。我正在使用 TLSwipeForOptionsCell
来触发编辑,但它很容易复制,例如 tableView:didSelectRowAtIndexPath:
-(void)hideEditFields{
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
editFormVisibleForRow = -1;
[self.tableView endUpdates];
}
-(void)cellDidSelectMore:(TLSwipeForOptionsCell *)cell{
NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
// do nothing if this is the currently selected row
if(editFormVisibleForRow != indexPath.row){
if(editFormVisibleForRow >= 0){
[self hideEditFields];
// update the index path, as the cell positions (may) have changed
indexPath = [self.tableView indexPathForCell:cell];
}
[self.tableView beginUpdates];
editFormVisibleForRow = indexPath.row;
[self.tableView insertRowsAtIndexPaths:@[
[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]
] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
}
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _dataSource.count + (editFormVisibleForRow >= 0 ? 1 : 0);
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
int row = indexPath.row;
if(editFormVisibleForRow >= 0 && row > editFormVisibleForRow && row <= editFormVisibleForRow + 1){
return 180.0f;
}
else return 60.0;
}
仔细研究了一下,这似乎是一个没有明确答案的常见问题。我在 SO 上发现的大多数类似问题都没有答案,或者提供了针对提问者情况的解决方法。 (示例:Problem with RowAnimation、Custom UITableViewCell height yields improper animation、UITableView animation glitch when deleting and inserting cells with varying heights)。
此外,我没有尝试制作一个三倍大小的编辑行,而是尝试制作三个较小的行并为它们设置动画,但这并不合适,因为它们都同时出现。我也尝试过一个接一个地为它们设置动画,但是缓动使它看起来很奇怪,出现了一个明显的三步动画,而不是整个编辑 View 在一个 Action 中滑出 View 。
编辑: 我刚刚注意到,如果我为我要设置动画的行上方的行调用 reloadRowsAtIndexPaths:withRowAnimation: UITableViewRowAnimationNone
,它会改变行为动画;即动画假定高度为 0pts,如下面的动画所示。它更接近我想要的,但仍然不对,因为动画速度是错误的并且留下了间隙(在我的应用程序中这意味着背景
颜色戳穿)
最佳答案
解决方案非常简单。您需要插入高度为 0
的单元格,然后将高度更改为预期大小,然后调用 beginUpdates
和 endUpdates
.
这是一些伪代码。
var cellHeight: CGFloat = 0
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let dynamicHeightIndex = 2
if indexPath.row == dynamicHeightIndex {
return cellHeight
} else {
return tableView.rowHeight
}
}
func insertCell() {
// First update the data source before inserting the row
tableView.insertRows(at: [someIndexPath], with: .none)
cellHeight = 200
tableView.beginUpdates()
tableView.endUpdates()
}
要删除单元格,您需要等到更新动画完成后再从 TableView 中删除。
在 iOS 11 中你有 func performBatchUpdates(_:completion:)
它提供了一个完成 block 。对于以前的版本,您可以尝试使用 CATransaction
完成。
cellHeight = 0
CATransaction.begin()
CATransaction.setCompletionBlock({
self.tableView.deleteRows(at: [someIndexPath], with: .none)
})
tableView.beginUpdates()
tableView.endUpdates()
CATransaction.commit()
关于ios - 假设高度错误,将较大的行插入 UITableView 时的动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19991460/