ios - 假设高度错误,将较大的行插入 UITableView 时的动画

标签 ios animation uitableview

我在为 UITableView 中与其他行具有不同高度的行添加或删除动画时遇到问题。

以下 gif 演示了插入和删除默认高度 (44pts) 行和更大行 (100pts) 的问题。左边的是模拟器的屏幕录像(新单元格最终覆盖第五行是另一回事),右边的是它应该做什么的模型。

gif of animation issue gif of how it should look

在我的例子中,我有一堆行,每行的高度为 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 RowAnimationCustom UITableViewCell height yields improper animationUITableView animation glitch when deleting and inserting cells with varying heights)。

此外,我没有尝试制作一个三倍大小的编辑行,而是尝试制作三个较小的行并为它们设置动画,但这并不合适,因为它们都同时出现。我也尝试过一个接一个地为它们设置动画,但是缓动使它看起来很奇怪,出现了一个明显的三步动画,而不是整个编辑 View 在一个 Action 中滑出 View 。

编辑: 我刚刚注意到,如果我为我要设置动画的行上方的行调用 reloadRowsAtIndexPaths:withRowAnimation: UITableViewRowAnimationNone,它会改变行为动画;即动画假定高度为 0pts,如下面的动画所示。它更接近我想要的,但仍然不对,因为动画速度是错误的并且留下了间隙(在我的应用程序中这意味着背景 颜色戳穿)

gif of issue with previous row reloaded

最佳答案

解决方案非常简单。您需要插入高度为 0 的单元格,然后将高度更改为预期大小,然后调用 beginUpdatesendUpdates .

这是一些伪代码。

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/

相关文章:

ios - 位于 tableview 顶部且不滚动但其他单元格在其下方滚动的标题 tableViewCell

ios - UITableViewCell 内容在单独重新加载单元格时闪烁

c++ - boolean 变量的最佳大小是多少

javascript - 通过改变类滑下动画

java - 按顺序播放帧动画。安卓

c - ncurses 新手 - 从 GNU C 开始

ios - 正在调用 cellForRowAtIndexPath : ever practical?

ios - 遍历 TableView 单元格?

ios - IOS 上的声音剪辑被截断

ios - 查看将消失 : Determine whether view controller is being popped or is showing a sub-view controller