insertRowsAtIndexPaths:with scrollToRowAtIndexPath:导致UITableView部分被错误地隐藏

时间:2012-07-17 02:48:51

标签: ios cocoa-touch uitableview uikit

我创建了一个UITableview,其中包含可点击的部分。当你点击它们时,

  1. 他们“扩展”以揭示其中的细胞
  2. 单击的部分滚动到视图的顶部。
  3. 我计算所有索引路径以插入/删除必要的单元格,然后使用以下代码插入它们:

    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation];
    [self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation];
    [self.tableView endUpdates];
    [self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0]  atScrollPosition:UITableViewScrollPositionTop animated:YES];
    

    只有一个问题 - 隐藏了所选部分下方的部分。第一个屏幕截图显示了tableview的外观。第二个屏幕截图显示了它的实际外观。

    Sections Disappear

    如果向上滚动(因此隐藏的部分在屏幕外),然后向下滚动,隐藏的部分将被带回(再次可见)。我猜测为什么会发生这种情况如下:

    插入/删除动画与scrollToRowAtIndexPath同时发生,并且使TableView混乱。如果我没有完成scrollToRowAtIndexPath部分3& 4会出现在屏幕外 - 因此tableView仍然认为它们在屏幕外。 UITableview将屏幕外的单元格/部分隐藏为优化。如果我用scrollToRowAtIndexPath拨打dispatch_after 2秒,则第3和第3部分4正确显示。

    所以我想我知道为什么会这样,但我不知道如何修复/覆盖这个UITableview优化。实际上,如果我实现scrollViewDidEndScrollingAnimation然后在此函数中添加断点,则应用程序会显示第3节和第3节。 4正确(这就是我第一次拍摄屏幕的方式)。但是一旦继续这个功能,细胞就会消失。

    可以下载整个项目here


    其他实现细节:Sections是合法的UITableView部分。我添加了一个tapGestureRecognizer,用于触发对tableview的委托回调。下面是打开各个部分的整个方法。

    - (void)sectionHeaderView:(SectionHeaderView *)sectionHeaderView sectionOpened:(NSInteger)sectionOpened
    {
        // Open
        sectionHeaderView.numRows = DefaultNumRows;
        sectionHeaderView.selected = YES;
        NSMutableArray *pathsToOpen = [[NSMutableArray alloc] init];
        for (int i = 0; i < sectionHeaderView.numRows; i++)
        {
            NSIndexPath *pathToOpen = [NSIndexPath indexPathForRow:i inSection:sectionOpened];
            [pathsToOpen addObject:pathToOpen];
        }
    
        // Close
        NSMutableArray *pathsToClose = [[NSMutableArray alloc] init];
        if (openSectionHeader)
        {
            for (int i = 0; i < openSectionHeader.numRows; i++)
            {
                NSIndexPath *pathToClose = [NSIndexPath indexPathForRow:i inSection:openSectionHeader.section];
                [pathsToClose addObject:pathToClose];
            }
        }
    
        // Set Correct Animation if section's already open
        UITableViewRowAnimation insertAnimation = UITableViewRowAnimationBottom;
        UITableViewRowAnimation deleteAnimation = UITableViewRowAnimationTop;
        if (!openSectionHeader || sectionOpened < openSectionHeader.section)
        {
            insertAnimation = UITableViewRowAnimationTop;
            deleteAnimation = UITableViewRowAnimationBottom;
        }
    
        openSectionHeader.numRows = 0;
        openSectionHeader.selected = NO;
        openSectionHeader = sectionHeaderView;
    
    
        [self.tableView beginUpdates];
        [self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation];
        [self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation];
        [self.tableView endUpdates];
        [self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0]  atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }
    

2 个答案:

答案 0 :(得分:6)

据我所知,返回已经使用过的剖面视图时会出现问题。而不是:

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section
{
    return [self.sectionHeaderViews objectAtIndex:section];
}

如果我每次创建一个新视图,我都没有问题:

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section{
    SectionHeaderView *sectionHeaderView = [self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName];
    sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", section];

    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)];
    [sectionHeaderView addGestureRecognizer:tapRecognizer];
    sectionHeaderView.section = section;
    sectionHeaderView.delegate = self;
    return sectionHeaderView;
}

可能会发生这种情况,因为您正在使用[self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName];创建节标题并在数组中保留它们,我认为UITableViewCell不是为其创建的,但我不确定。您可能需要考虑前面的UITableViewCell用于剖面视图,而是使用其他东西(可能是带有UILabel的UIImageView)。或者你不能将剖面视图存储在一个数组中...你目前设置代码的方式,你不需要数组并创建一个新视图是微不足道的,你不需要担心它。

答案 1 :(得分:4)

@AaronHayman的回答是有效的(和IMO的接受和赏金应该归他所有 - 因为它只是不适合评论!),但我会更进一步 - 你不应该根本不使用单元格用于节头,你不应该使用出列机制来实际加载一个笔尖。

节标题视图不应该是单元格,并且您可以通过使用它们代替常规视图来获得不可预见的效果,特别是如果它们被取消 - 表格会在您执行此操作时保留这些可重用单元格的列表,并且当它们离开屏幕时回收它们,但是您的节标题不是可重复使用,每个部分有一个。

在您的示例项目中,我将SectionHeaderView的超类更改为普通的UIView,并将您的createSectionHeaderViews方法更改为直接从那里的nib加载:

NSMutableArray *sectionHeaderViews = [[NSMutableArray alloc] init];
    UINib *headerNib = [UINib nibWithNibName:SectionHeaderView_NibName bundle:nil];
    for (int i = 0; i < 5; i++)
    {
        SectionHeaderView *sectionHeaderView = [[headerNib instantiateWithOwner:nil options:nil] objectAtIndex:0];
        sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", i];

        UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)];
        [sectionHeaderView addGestureRecognizer:tapRecognizer];
        sectionHeaderView.section = i;
        sectionHeaderView.delegate = self;

        [sectionHeaderViews addObject:sectionHeaderView];
    }
    self.sectionHeaderViews = sectionHeaderViews;

我还从viewDidLoad中注释了重用行的注册表。这可以防止节标题消失。