5

我的问题是关于删除 UITableView 中的“不可见”行。当我说不可见时,我的意思是屏幕上没有显示的行。例如调用 UITableView 方法没有返回的所有行- (NSArray *)visibleCells

我问这个是因为我正在开发一个“可扩展”的 UITableView。有点像一棵树。你可以有一个这样的表:

  • 菜单 1
    1. 菜单 1.1
    2. 菜单 1.2
  • 菜单 2
    1. 菜单 2.1
    2. 菜单 2.2

当您单击"Menu 1"单元格时"Menu 1.1""Menu 1.2"将出现或消失。我通过简单地插入或删除带有动画的单元格来做到这一点。

问题是,如果我有长菜单并且用户滚动,例如,如果“菜单 1”中的一半行隐藏(不可见,不显示在屏幕上,只有向下滚动时可见)并且用户想要减少“菜单 1”,这将导致我的应用程序崩溃,因为我试图删除不可见的行。

实际的错误信息是:

*由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (11) 必须等于其中包含的行数更新前的那个节 (15),加上或减去从该节插入或删除的行数(0 插入,0 删除),加上或减去移入或移出该节的行数(0 移入,0搬出)。'

如果我对所有可见的行进行完全相同的操作,则应用程序没有问题并且菜单行为正确。

4

3 回答 3

1

在您的 tableview 更新调用中,您需要更新 tableview 数据源以及 tableview。您可以使用 UITableView 的 indexPathsForVisibleRows 方法来查找要从源中删除对象的位置,并更新您的表。

于 2013-06-03T18:26:25.403 回答
0

感谢大家的回答。我所做的是我使用“indexPathsForVisibleRows”来获取屏幕上显示的行的 indexPaths,我只是更新了我的模型并调用了“reloadData”来更新我的表。这不是我期待的理想解决方案,但它有效。

我仍然不明白为什么“-deleteRowsAtIndexPaths”不适用于不在屏幕上但实际上确实存在于表中的行。

于 2013-06-04T15:26:04.203 回答
0

我有一个类似的问题,这是我的解决方案。基本上,解决方案涉及更改单元格高度以“隐藏”它们。

我已将部分标题更改为自定义 UIControl,使其看起来像任何其他单元格,并实现了以下方法来“隐藏”所选部分之外的行:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == _selectedSection) {
        // If it is the selected section then the cells are "open"
        return 60.0;
    } else {
        // If is not the selected section then "close" the cells
        return 0.0;
    }
}

对于自定义标头,我使用了以下代码:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    CGFloat height = [self tableView:tableView heightForHeaderInSection:section];

    // Here you can use whatever you want
    CGFloat width = 640.0;

    UIControl *view = [[UIControl alloc] initWithFrame:CGRectMake(0.0, 0.0, width, height)];

    view.tag = section;

    // This code is used by my custom UIControl
    //
    // to change the style for each state
    // view.sectionSelected = (section == _selectedSection);
    //
    // and to change the title
    // view.title = [self tableView:tableView titleForHeaderInSection:section];

    // This event is used to "close" or "open" the sections
    [view addTarget:self action:@selector(didSelectSectionHeader:) forControlEvents:UIControlEventTouchUpInside];

    return view;
}

为了更吸引人,我在以下方法中添加了动画:

- (void)didSelectSectionHeader:(id)sender
{
    if ([sender isKindOfClass:[UIControl class]]) {
        // Save the old section index
        int oldSelection = _selectedSection;

        // Get the new section index
        int tag = ((UIControl *)sender).tag;

        // Get sections quantity
        int numSections = [self numberOfSectionsInTableView:_tableView];

        // Check if the user is closing the selected section
        if (tag == _selectedSection) {
            _selectedSection = -1;
        } else {
            _selectedSection = tag;
        }

        // Begin animations
        [_tableView beginUpdates];

        // Open the new selected section
        if (_selectedSection >= 0 && _selectedSection < numSections) {
            [_tableView reloadSections:[NSIndexSet indexSetWithIndex:_selectedSection] withRowAnimation:UITableViewRowAnimationAutomatic];
        }

        // Close the old selected section
        if (oldSelection >= 0 && oldSelection < numSections) {
            [_tableView reloadSections:[NSIndexSet indexSetWithIndex:oldSelection] withRowAnimation:UITableViewRowAnimationAutomatic];
        }

        [_tableView endUpdates];
    }
}
于 2013-06-04T15:55:03.257 回答