删除和插入具有不同高度的单元格时,UITableView 动画故障

Posted

技术标签:

【中文标题】删除和插入具有不同高度的单元格时,UITableView 动画故障【英文标题】:UITableView animation glitch when deleting and inserting cells with varying heights 【发布时间】:2013-01-24 01:16:09 【问题描述】:

我在同时删除和插入单元格时遇到了 UITableView 提供的动画问题。 我有一个单元格列表,可以称它们为问题。当一个问题被点击时,它应该在其下方添加一个单元格以显示该问题的答案。如果已显示另一个答案,则应从表中删除该答案。 当插入的单元非常高时,就会出现问题。如果它太高以至于最终边界侵占了要删除的单元格占用的空间,那么在动画过程中,我们会看到我们正在删除的答案单元格以查看正在添加的单元格

(see link to video of problem)

这就是我的代码在表格视图中的单元格周围移动的样子

[tableView beginUpdates];

if (deleteIndex) 
    [tableView deleteRowsAtIndexPaths:@[deleteIndex] withRowAnimation:UITableViewRowAnimationTop];

if (addIndex) 
[tableView insertRowsAtIndexPaths:@[addIndex] withRowAnimation:UITableViewRowAnimationTop];


[tableView endUpdates];

我试过了

[tableView beginUpdates];

if (deleteIndex) 
    [tableView deleteRowsAtIndexPaths:@[deleteIndex] withRowAnimation:UITableViewRowAnimationTop];

[tableView endUpdates];

//do stuff to update data source

[tableView beginUpdates];

if (addIndex) 
[tableView insertRowsAtIndexPaths:@[addIndex] withRowAnimation:UITableViewRowAnimationTop];


[tableView endUpdates];

但是因为在开始第二个块之前没有确认表视图确实完成了第一个集合更新的回调,所以会发生几乎相同的问题。我知道我可以使用延迟执行选择器,但这似乎是一个创可贴。

第二次我尝试将动画包含在这样的块中

[UIView animateWithDuration:0.0 animations:^
    [tableView beginUpdates];

    if (deleteIndex) 
        [tableView deleteRowsAtIndexPaths:@[deleteIndex] withRowAnimation:UITableViewRowAnimationTop];
    
    [tableView endUpdates];

    //do stuff to update data source

 completion:^(BOOL finished) 

    [tableView beginUpdates];

    if (addIndex) 
        [tableView insertRowsAtIndexPaths:@[addIndex] withRowAnimation:UITableViewRowAnimationTop];
    

    [tableView endUpdates];
];

再一次,因为完成块是在我们调用 endUpdates 之后触发的,而不是在更新实际完成之后,这并不能解决使用问题。

我还进入了故事板,以确保为单元格选择了剪辑子视图到边界。同样,这并不能解决问题,因为我们没有看到单元格的子视图扩展超出其预期高度。

通过放慢动画仔细观察动画,看起来苹果将要添加的单元格插入到表格中不会更改的单元格下方,然后将保留的单元格移动到新位置。结果,被删除的单元格变成了一个透明窗口,我们可以在其中看到他们在后台实际执行的操作。

【问题讨论】:

【参考方案1】:

正确的做法是先删除旧答案,然后在动画结束后添加新答案。有一个 UITableViewDelegate 方法,在单元格动画完成后触发。

tableView:didEndDisplayingCell:forRowAtIndexPath:

在此委托方法中插入新的答案行将产生正确的动画。

有一些细节需要牢记 - 您需要一些逻辑来确保返回正确的单元格高度并返回该部分中正确的预期行数。这些数据源方法是在我们删除旧答案后调用的,当我们调用时添加新答案时会再次调用这些数据源方法

endUpdates

在表格视图上

使用 UITableViewRowAnimationTop 以外的任何东西都会导致一些奇怪的动画行为。这是因为单元格的内容视图不是动画。

【讨论】:

问题是tableView:didEndDisplayingCell:forRowAtIndexPath: 在用户将部分滚动出屏幕时也会被触发【参考方案2】:

我通过隐藏控件解决了我的项目中的相同问题,例如: 在 ~cell.m 中有

(void)setSelected:(BOOL)selected animated:(BOOL)animated;


if(selected == NO)

    self.selectedView.hidden = YES;
    self.descriptionLabel.hidden = YES;


else

    self.selectedView.hidden = NO;
    self.descriptionLabel.hidden = NO;



还是有用的

【讨论】:

以上是关于删除和插入具有不同高度的单元格时,UITableView 动画故障的主要内容,如果未能解决你的问题,请参考以下文章

如何拥有两个具有两个不同高度的独立单元? [复制]

插入/删除顶部/底部单元格时更新旧/新顶部/底部单元格的 backgroundView

在具有动态高度的 IB uitableviewcell 中使用带有 XIB 的自定义视图

UITableViewCell 具有嵌入式垂直堆栈视图设置,具有自动布局和动态高度

添加具有行动画的单元格时,将 tableview 保持在相同的滚动位置

RowAnimation 使用不同高度的单元格看起来很奇怪