UITableView 删除并重新加载单元格

Posted

技术标签:

【中文标题】UITableView 删除并重新加载单元格【英文标题】:UITableView delete and reload cells 【发布时间】:2012-09-02 16:22:05 【问题描述】:

我正在像这样删除 UITableView 中的一些行:

[tableView deleteRowsAtIndexPaths:toDelete withRowAnimation:UITableViewRowAnimationAutomatic];

这为删除操作添加了一个漂亮的动画。

但是,删除后我需要更新所有当前可见的行。调用

[tableView reloadData];

第一次调用后就可以了,但是漂亮的动画效果就消失了。有什么更好的方法来做到这一点?即,为删除操作设置动画,并更新所有当前可见的行? 谢谢!

我需要这样做的原因是因为每个单元格都包含一个“复选框”。我的视图控制器是复选框的代表,每个复选框都有一个与之关联的 NSIndexPath。当复选框被切换时,会调用委托,告诉它我们切换了 x 索引路径。现在,如果删除了某些行,则需要更新索引路径。这就是为什么我需要重新加载所有内容,以便每个复选框都知道它所属的位置。

【问题讨论】:

为什么删除后需要强制重新加载? (您不能在调用 deleteRowsAtIndexPaths 之前从数据源中删除该行,还是发生了更重要的事情?) 我不记得它是否有效,但您是否尝试过进行模型级删除,然后简单地将 reloadData 包装在 [UIView animateWithDuration...] 块中? @middaparka 我会更新我的问题,解释为什么我需要这样做。 @ctrahey 这是正确的方法吗? @ctrahey 使用动画块有效,但在持续时间内传递的正确值是多少? 【参考方案1】:

在您的删除操作中使用 performBatchUpdates 而不是 [tableView beginUpdates] 这允许您有一个完成块

将多个插入、删除、重新加载和移动操作动画化为 组。

self.tableView.performBatchUpdates(
     //do stuff then delete the row
     self.tableView.deleteRows(at: [indexPath], with: .fade)
, completion:  (done) in
     //perform table refresh
     self.tableView.reloadData()

)

【讨论】:

【参考方案2】:

ctrahey 的动画块无论经过多长时间都对我不起作用。研究了UITableView的delete, insert & reload的机制。我在 Github 上维护我的项目来解决这个问题。

https://github.com/VansonLeung/VanTableController

其中包含一个工作单元测试。通常为了给 UITableView 的单元格动画设置动画,我们必须这样做:

[tableView_ beginUpdates];
[tableView_ deleteRowsAtIndexPaths: indexPathDelete withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView_ insertRowsAtIndexPaths: indexPathInsert withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView_ reloadRowsAtIndexPaths: indexPathReload withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView_ endUpdates];

我们必须确定删除行、插入行和重新加载行的 indexPath 数组,这是一项非常讨厌的工作!我的项目工作基本上是生成这些 indexPaths 的包装器。

【讨论】:

【参考方案3】:

注意: 如 cmets 中所述,此答案可能不起作用。如果不被接受,我会删除它。

我不能 100% 确定这是执行此操作的最佳方法,但它有一些令人愉快的清洁。修改底层模型后,我们可以将reloadData 包裹在一个常规的 UIView 动画块中:

// if self.people is a mutable array
[self.people removeObjectAtIndex:13];

[UIView animateWithDuration:0.5 animations:^
  [self.tableView reloadData];
];

【讨论】:

正如 Vanson Wing Leung 指出的那样,无论经过哪个持续时间,这都行不通... 我假设这不起作用的原因是因为 reloadData 不是 UIView 的动画属性,而是您想将其更改为此,这应该可以正常工作:[self.tableView performSelector:@selector(reloadData) withObject:nil afterDelay:0.14];跨度> 【参考方案4】:

我遇到了一些与此相关的问题。使用固定索引可能你会面临很多头痛。我已经解决了这个问题,向 UITableViewCell 添加了对我的数据源中的项目的引用,而不是 NSIndexPath。因此,无需使用保存到单元格中的 indexPath。

另外,Apple 的网站上有一些信息说我们不能在插入或删除方法中使用方法 reloadData

Apple docs

all 这个方法重新加载所有用于构造表格的数据,包括单元格、节页眉和页脚、索引数组等。为了提高效率,表格视图只重新显示那些可见的行。如果表因重新加载而缩小,它会调整偏移量。表视图的委托或数据源在它希望表视图完全重新加载其数据时调用此方法。不应在插入或删除行的方法中调用它,尤其是在通过调用 beginUpdates 和 endUpdates 实现的动画块中

【讨论】:

以上是关于UITableView 删除并重新加载单元格的主要内容,如果未能解决你的问题,请参考以下文章

重新加载 UITableView 数据并向下滚动到最后选择的单元格

UITableView 在 TableView 中间加载单元格。为啥?

批量插入和删除 + 重新加载旧单元格 = 例外

将uitableview重新加载到底部单元格

UITableView 重新加载除一个以外的所有单元格

重新加载 UITableView 数据而不是可见单元格