UITableView:并置行,页眉和页脚插入/删除

时间:2010-05-18 15:27:29

标签: ios iphone uitableview row

考虑一个非常简单的 UITableView ,其中包含两种状态之一。

第一个州:

  • 一个(整体)表格页脚
  • 包含两行,一个部分标题和一个部分页脚
  • 的一个部分

第二州:

  • 没有桌面页脚
  • 一个部分包含四行而没有部分页眉/页脚

在这两种情况下,每一行基本上都是四个可能的 UITableViewCell 对象中的一个,每个对象都包含自己的 UITextField 。我们甚至不需要重用或缓存,因为在这种情况下我们只处理四个已知单元。它们是在随附的XIB中创建的,因此我们已经将它们全部连接好并准备好了。

现在考虑我们要在两种状态之间切换。

听起来很容易。让我们假设我们的视图控制器的右侧栏按钮项提供切换支持。我们还将使用ivar和枚举来跟踪当前状态。

要明确一秒,这是一个人如何从状态1转到2.(假设我们也处理条形按钮项目的标题。)简而言之,我们要清除表格的页脚视图,然后插入第三和第四行。我们在更新块中批量处理,如下所示:

// Brute forced references to the third and fourth rows in section 0
NSUInteger row02[] = {0, 2};
NSUInteger row03[] = {0, 3};

[self.tableView beginUpdates];
state = tableStateTwo; // 'internal' iVar, not a property
self.tableView.tableFooterView = nil;
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:
    [NSIndexPath indexPathWithIndexes:row02 length:2],
    [NSIndexPath indexPathWithIndexes:row03 length:2], nil]
    withRowAnimation:UITableViewRowAnimationFade];  
[self.tableView endUpdates];

反过来说,我们想要重新分配表格页脚视图(就像单元格一样,在XIB中准备就绪并等待),并删除最后两行:

// Use row02 and row03 from earlier snippet

[self.tableView beginUpdates];  
state = tableStateOne;
self.tableView.tableFooterView = theTableFooterView;
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:
    [NSIndexPath indexPathWithIndexes:row02 length:2],
    [NSIndexPath indexPathWithIndexes:row03 length:2], nil]
    withRowAnimation:UITableViewRowAnimationFade];  
[self.tableView endUpdates];

现在,当桌子要求行时,它非常干净。前两个细胞在两种情况下都是相同的。根据状态,只有最后两个出现/消失。当表视图询问诸如节中的行数,节中页眉/页脚的高度或节中页眉/页脚的视图之类的内容时,将查询状态ivar。

最后一点也是我遇到麻烦的地方。

使用上述逻辑,0部分的页眉/页脚不会消失。具体来说,页脚保持在插入行的下方,但标题现在覆盖最顶行。如果我们切换回状态1,则删除部分页脚,但部分标题仍然存在。

那么使用[self.tableView reloadData]怎么样?当然,为什么不呢。根据Apple的建议,我们注意不要在更新块中使用它,只需在endUpdates之后添加它。

这一次,好消息!第0节页眉/页脚消失。 :)

然而......

切换回状态导致最精致的混乱!第0节标题返回,只是再次覆盖第一行(而不是显示在它上面)。第0节的页脚位于最后一行的下方,但整个表格页脚 - 现在已恢复 - 覆盖了页面页脚。 Waaaaaah ......现在怎么样?

为了确保,让我们再次切换回状态二。是的,看起来很好。回到州一? Yecccch。

我也试过像其他一些特技一样使用reloadSections:withRowAnimation:,但这只会让事情变得更糟。

NSRange range = {0, 1};
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];

...

[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationFade];

例证:如果我们在更新块结束之前调用reloadSections...,则更改为状态2会隐藏视图中的前两行,即使它们原本占用的空间仍然存在。切换回状态1会将第0部分的页眉/页脚返回到正常状态,但前两行仍然不可见。

案例二:将reloadSections...移至更新块之后但reloadData之前导致所有行变为不可见! (我将该行称为不可见,因为在跟踪期间,tableView:cellForRowAtIndexPath: 为这些行返回真正的单元格对象。)

案例三:在reloadSections...之后移动tableView:cellForRowAtIndexPath:使我们更接近,但是当切换回状态1时,第0节页眉/页脚永远不会返回。

嗯。根据我在追踪时所看到的情况,使用reloadSections... reloadData可能会造成失礼,这会带来我们:

案例四:直接用reloadData替换reloadSections...。状态二中的所有细胞都消失了。状态1中的所有单元格也保持缺失(尽管保留空间)。

这个理论太多了。 :)

跟踪代码,单元格和视图对象以及区域高度,都是适合他们应该在适当的时间。他们只是没有表现得很清醒。 (更新:视图高度不一样,但我也没有更改它们!有关详细信息,请参阅我发布的答案。)

那么,如何破解这种情况呢?线索欢迎/赞赏!

2 个答案:

答案 0 :(得分:1)

我今天遇到了同样的问题。

过了一会儿,我想到了一切都画得错误的想法。在表视图单元格方法的外观中,我删除了这样的条件子句,一切正常:

    //if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];    
    //}

我将仔细研究这个问题,因为代码现在不再优化了。但它暂时有效。

答案 1 :(得分:0)

我把它放在答案部分,因为它有助于(部分?)解释我所看到的内容。它只是没有解释为什么。 :)

当我第一次将视图分配给表部分标题时(响应tableView:viewForHeaderInSection:),它的设置就像我在XIB中定义它一样:

<UIView: 0x376620; frame = (0 0; 320 50); autoresize = RM+BM;
 layer = <CALayer: 0x376720>>

在我们更改单元格并开始响应第0部分的nil为tableView:viewForHeaderInSection:之后的某个时间,所述视图获得了一些 CABasicAnimation 的爱(毕竟表格即将动画) ...并且视图框架和autoresize参数更改!

<UIView: 0x376620; frame = (0 0; 320 10); autoresize = W; 
 animations = { position=<CABasicAnimation: 0x360b30>;
 bounds=<CABasicAnimation: 0x360a30>; }; layer = <CALayer: 0x376720>>

如果我们再将BACK切换到第一个状态,并再次返回与节标题相同的视图,我们会在分配时看到一些碎片:

<UIView: 0x376620; frame = (0 0; 320 10); autoresize = W; 
 layer = <CALayer: 0x376720>>

是的。框架和自动调整大小不会重置!

因此,当从表的节头中有效删除视图时,我们似乎已经遇到了无意的副作用。

我的下意识反应:“如果你要弄乱我的UIView,请把东西放回你找到它们的方式!”在这一点上,我不知道这是否是一个现实的期望,但它是第一个想到的。

为了缓解,我想我每次都必须重置帧并自动调整大小。嗯......看起来有点乱,你想?也许有更好的方法,或者我在其他地方犯了一个失礼。

然后,此帧/自动调整大小调整似乎不会对整个表头/页脚视图造成问题,即使它们被删除并稍后重新添加。只是部分页眉/页脚视图。 (等等,更正:我无法判断它是否会影响表格页脚视图,因为它下方没有任何内容可以与之发生冲突。)

现在,我在每个页眉/页脚视图中嵌入了另一个视图。此视图在形式上与父视图相同,但在动画时不会更改。然后,对于受状态变化影响的每个页眉/页脚视图,只需调用类似于此的内容:

- (void)fixViewAnimationCruft:(UIView *)theView {
  UIView *subview = [[theView subviews] objectAtIndex:0];
  theView.frame = subview.frame;
  theView.autoresizingMask = subview.autoresizingMask;
}

(不是最原始的方法名称,但现在可以使用。)

相关问题