【问题标题】:How to delete rows from UITableView with animation?如何使用动画从 UITableView 中删除行?
【发布时间】:2013-02-07 10:15:25
【问题描述】:

我在从表视图中删除行时遇到问题。当按下行中的删除按钮时,我正在使用下面的代码:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:control.tag-100 inSection:0];
[resultList removeObjectAtIndex:indexPath.row];
[resultView beginUpdates];
[resultView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[resultView endUpdates];
//[resultView reloadData];

第一行已成功删除,但随后索引不正确。所以当我删除最后一行时,它会给出索引越界异常。

单元格生成代码为:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"personalizeTableCell";

    PersonalizeCell *cell = (PersonalizeCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
        cell = [[PersonalizeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];        
    cell.title.text = @"text";
    cell.rateView.tag = indexPath.row + 100;
    return cell;
}

我哪里错了?

更新:

    for (NSInteger j = 0; j < [venuesTableView numberOfSections]; ++j)
    {
        for (NSInteger i = 0; i < [venuesTableView numberOfRowsInSection:j]; ++i)
        {
           PersonalizeCell* cell = (PersonalizeCell*)[venuesTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]];
           cell.rateView.tag = 100 + i;
        }
    }

解决了我的问题。感谢 Nenad M.

【问题讨论】:

    标签: uitableview delete-row


    【解决方案1】:

    假设您的 [NSIndexPath indexPathForRow:control.tag-100 inSection:0]; 返回正确的索引路径.... 您是否尝试将 removeObjectAtIndex 调用移动到 begin-/end-updates “括号”内?:

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:control.tag-100 inSection:0];
    [resultView beginUpdates];
    [resultList removeObjectAtIndex:indexPath.row];
    [resultView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [resultView endUpdates];
    

    更新:

    在您删除第一个单元格后,您的cell.rateView.tag 显然是错误的。 因此,在每次删除(即每个removeObjectAtIndex...)之后,您必须重新遍历剩余的 tableview-cells 并重新分配正确的标签值(cell.rateView.tag = indexPath.row + 100)!否则您的[NSIndexPath indexPathForRow:control.tag-100 inSection:0]; 将返回错误的 indexPath,从而导致您的越界错误!

    重新分配标签值:

    您不必重新加载整个表格,只需遍历剩余的单元格并在 [resultView endUpdates]; 之后重新分配标记值:

    NSMutableArray *cells = [[NSMutableArray alloc] init];
    for (NSInteger j = 0; j < [tableView numberOfSections]; ++j)
    {
        for (NSInteger i = 0; i < [tableView numberOfRowsInSection:j]; ++i)
        {
            [cells addObject:[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
        }
    }
    

    现在做:

    for (PersonalizeCell* cell in cells)
    {
        cell.rateView.tag = // new calculated tag
    }
    

    (或者直接在第一个code-sn-p的内循环中重新赋值。)


    这是整个过程的一些非常典型的代码,示例中的表格中的两行:

    请注意,facebookRowsExpanded 是您必须拥有的类变量:

    if ( [theCommand isEqualToString:@"fbexpander"] )
    {
    NSLog(@"expander button......");
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    
    NSArray *deleteIndexPaths;
    NSArray *insertIndexPaths;
    
    facebookRowsExpanded = !facebookRowsExpanded;
    // you must do that BEFORE, not AFTER the animation:
    
    if ( !facebookRowsExpanded ) // ie, it was just true, is now false
        {
        deleteIndexPaths = [NSArray arrayWithObjects:
                [NSIndexPath indexPathForRow:2 inSection:0],
                [NSIndexPath indexPathForRow:3 inSection:0],
                 nil];
        [tableView beginUpdates];
        [tableView
            deleteRowsAtIndexPaths:deleteIndexPaths
            withRowAnimation: UITableViewRowAnimationMiddle];
        [tableView endUpdates];
        }
    else
        {
        insertIndexPaths = [NSArray arrayWithObjects:
                [NSIndexPath indexPathForRow:2 inSection:0],
                [NSIndexPath indexPathForRow:3 inSection:0],
                 nil];
        [tableView beginUpdates];
        [tableView
            insertRowsAtIndexPaths:insertIndexPaths
            withRowAnimation: UITableViewRowAnimationMiddle];
        [tableView endUpdates];
        }
    
    // DO NOT do this at the end: [_superTableView reloadData];
    return;
    }
    

    注意:numberOfRowsInSection 的代码必须使用 facebookRowsExpanded

    (类似于“如果 facebookRowsExpanded 返回 7,否则返回 5”)

    注意:cellForRowAtIndexPath 的代码必须使用 facebookRowsExpanded。

    (它必须返回正确的行,取决于您是否展开。)

    【讨论】:

    • 在最后一行之前一切正常。当谈到最后一行时,它又卡住了。我猜,删除行后,标签不会重新分配
    • 是的,因此我应该重新加载表。如果我重新加载,动画就不会发生