5

我创建了一个带有可点击部分的 UITableview。当你点击它们时,

  1. 它们“扩展”以显示其中的细胞
  2. 单击的部分滚动到视图的顶部。

我计算所有索引路径以插入/删除必要的单元格,然后使用以下代码插入它们:

[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 的外观。第二个屏幕截图显示了它的实际外观。

部分消失

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

插入/删除动画与 TableView 同时发生scrollToRowAtIndexPath,这使 TableView 感到困惑。如果我没有完成scrollToRowAtIndexPath第 3 节和第 4 节,就会出现在屏幕外——所以 tableView 仍然以某种方式认为它们在屏幕外。UITableview 隐藏了屏幕外的单元格/部分作为优化。如果我用 2 秒调用scrollToRowAtIndexPatha ,则第 3 和第 4 部分将正确显示。dispatch_after

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

完整的项目可以在这里下载


附加实现细节:部分是合法的 UITableView 部分。我添加了一个触发对 tableview 的委托回调的 tapGestureRecognizer。下面包括打开这些部分的整个方法。

- (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];
}
4

2 回答 2

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)。或者您可以不将剖面视图存储在数组中......您当前设置代码的方式,您不需要数组并且创建新视图很简单,您无需担心它。

于 2012-07-19T17:30:37.380 回答
5

@AaronHayman 的回答有效(IMO 的接受和赏金应该归他所有,就目前而言 - 这只是不适合评论!),但我会更进一步 - 你不应该在部分使用单元格标头,并且您不应该使用出队机制来实质上加载笔尖。

节标题视图不应该是单元格,使用它们代替常规视图可能会产生无法预料的效果,特别是如果它们被 deqeueued - 当您这样做时,表格会保留这些可重用单元格的列表,并回收它们当它们离开屏幕,但您的部分标题不可重复使用时,每个部分都有一个。

在您的示例项目中,我将 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 中注释掉了 register for reuse 行。这可以防止节标题消失。

于 2012-07-20T11:44:17.717 回答