UITableView deleteRowsAtIndexPaths & reloadRowsAtIndexPaths等方法遇到诡异的问题

  • 背景

    需求要实现一个列表中cell被删除的动画效果,UI要求cell之间有 10pt的间隔,所以通过在自定义cell的setFrame方法中修改fram的height 达到了分段的tableView效果。
image.png
  • 问题

    在调用了deleteRowsAtIndexPaths和reloadRowsAtIndexPaths后, 发现cell的高度被多次修改导致 fram比预计的小了10pt(分段间隔的高度)
image.png
  • 原因

先说原因 重载部分cell、删除cell、插入cell的动作是在原来cell的位置用新的cell替换,原cell的height已经调用setFrame,新的cell也会走一遍setFrame,所以最后会发现 可视的所有cell都会出现间隔放大10pt(fram.size.height 小了10pt)

  • 解决方案

放弃在setframe中修改fram的实现cell分段的间隔效果的方式,而是在contentview中布局实现(添加view类似,不再赘述)。
缺点:如果cell 有整体的点击效果或者左滑动业务会导致间隔也在操作范围内,尤其是由于点击背景色时。



重新了解下这几个方法:

  - (void)beginUpdates;
  - (void)endUpdates;
  -  (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
  - (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
  - (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
  - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;
  - (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation: (UITableViewRowAnimation)animation;
  - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;

The UITableView class allows you to insert, delete, and reload a group of rows or sections at one time, animating the operations simultaneously in specified ways. The eight methods shown in Listing 7-7 pertain to batch insertion and deletion. Note that you can call these insertion and deletion methods outside of an animation

文档告诉我们

UITableView允许您一次插入、删除和重新加载 部分rows或者sections ,同时指定动画的操作方式。上面所示的八个方法适合批量插入和删除。注意,您可以调用这些插入和删除方法之外的一个动画

demo about Inserting and deleting a block of rows in a table view

> - (IBAction)insertAndDeleteRows:(id)sender {
    // original rows: Arizona, California, Delaware, New Jersey, Washington
 
    [states removeObjectAtIndex:4]; // Washington
    [states removeObjectAtIndex:2]; // Delaware
    [states insertObject:@"Alaska" atIndex:0];
    [states insertObject:@"Georgia" atIndex:3];
    [states insertObject:@"Virginia" atIndex:5];
 
    NSArray *deleteIndexPaths = [NSArray arrayWithObjects:
                                [NSIndexPath indexPathForRow:2 inSection:0],
                                [NSIndexPath indexPathForRow:4 inSection:0],
                                nil];
    NSArray *insertIndexPaths = [NSArray arrayWithObjects:
                                [NSIndexPath indexPathForRow:0 inSection:0],
                                [NSIndexPath indexPathForRow:3 inSection:0],
                                [NSIndexPath indexPathForRow:5 inSection:0],
                                nil];
    UITableView *tv = (UITableView *)self.view;
 
    [tv beginUpdates];
    [tv insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
    [tv deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
    [tv endUpdates];
 
    // ending rows: Alaska, Arizona, California, Georgia, New Jersey, Virginia
}

操作的执行顺序
在上面的例子中,你肯定注意到 deleteRowsAtIndexPaths:withRowAnimation:方法写在 insertRowsAtIndexPaths:withRowAnimation:之后。然而,这并不是tableView真正的操作顺序。实际上,所有的插入和重载都会在删除动作完成之后才执行

上面的使用场景是我们经常会用到的,但是大家使用过程中要结合实际场景比如:
1.如果你的操作是通过cell 的block回调传递indexPath实现的话,就需要考虑前面执行的cell在删除和增加之后 是否需要重新配置后面cell已经拿到的indexPath,否则可能导致数组越界的问题。
2.如果deleteRowsAtIndexPaths:的row为该section的最后一行(indexPath.row = 0),就需要调用deleteSections:删除整个section。

总结来说:在执行删除和插入之前,把数据源必须准确完善。数据源操作的个数和cell操作个数必须对应。

你可能感兴趣的:(UITableView deleteRowsAtIndexPaths & reloadRowsAtIndexPaths等方法遇到诡异的问题)