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

Ios UITableView:并置行、页眉和页脚插入/删除,ios,iphone,uitableview,row,Ios,Iphone,Uitableview,Row,考虑一个非常简单的具有两种状态之一的UITableView 第一个国家: 一个(全部)表尾 一个包含两行的节、一个节页眉和一个节页脚 第二个国家: 无表尾 一个节包含四行,没有节页眉/页脚 在这两种情况下,每一行基本上是四个可能的UITableViewCell对象之一,每个对象都包含自己的UITextField。我们甚至不用担心重用或缓存,因为在本例中我们只处理四个已知单元。它们是在一个附带的XIB中创建的,所以我们已经将它们全部连接起来并准备就绪 现在我们想在这两个状态之间切换。< /

考虑一个非常简单的具有两种状态之一的UITableView

第一个国家:

  • 一个(全部)表尾
  • 一个包含两行的节、一个节页眉和一个节页脚
第二个国家:

  • 无表尾
  • 一个节包含四行,没有节页眉/页脚
在这两种情况下,每一行基本上是四个可能的UITableViewCell对象之一,每个对象都包含自己的UITextField。我们甚至不用担心重用或缓存,因为在本例中我们只处理四个已知单元。它们是在一个附带的XIB中创建的,所以我们已经将它们全部连接起来并准备就绪

现在我们想在这两个状态之间切换。< /P> 听起来很简单。让我们假设视图控制器的右栏按钮项提供了切换支持。我们还将使用ivar和枚举跟踪当前状态

为了明确起见,下面是一个人如何从状态1变为状态2。(假设我们也处理bar按钮项的标题。)简言之,我们希望清除表的页脚视图,然后插入第三行和第四行。我们在更新块中批处理此内容,如下所示:

// 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]
怎么样?当然,为什么不呢。按照苹果的建议,我们注意不要在更新块中使用它,只需在
endUpdates
之后添加它即可

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

然而

切换回状态1会导致一个非常精致的混乱!第0节标题返回,只会再次覆盖第一行(而不是显示在其上方)。第0节的页脚正好放在最后一行的下方,但整个表的页脚(现在已恢复)覆盖在该节的页脚上。哇…现在怎么办

为了确定,让我们再次切换回第二种状态。是的,看起来不错。回到第一州?是的

我还尝试了一些其他特技,比如使用
重载部分:withRowAnimation:
,但这只会让事情变得更糟

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

...

[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
举个例子:如果我们在更新块结束之前调用
reloadSections…
,更改为state two会将前两行隐藏在视图中,即使它们本来会占用的空间仍然存在。切换回状态1会使节0的页眉/页脚恢复正常,但前两行仍然不可见

案例二:将
reloadSections…
移动到更新块之后但在
reloadData
之前会导致所有行变为不可见!(我将该行称为不可见,因为在跟踪过程中,
tableView:cellforrowatinexpath:
正在为这些行返回真正的单元格对象。)

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

嗯。根据我在跟踪时看到的情况,可能是使用
重新加载部分…
重新加载数据
的失礼行为,这让我们想到:

案例四:将
reloadData
完全替换为
reloaddsections…
。处于第二状态的所有细胞都消失了。状态1中的所有单元格也将丢失(尽管保留了空间)

这个理论到此为止。:)

通过代码跟踪,单元格和视图对象以及截面高度都是它们在适当的时候应该位于的位置。他们只是表现得不理智。(更新:视图高度不一样,但我也没有更改它们!有关更多信息,请参阅我发布的答案。)


那么,如何破案呢?欢迎/感谢

我把这个放在回答部分,因为它有助于(部分?)解释我所看到的。这还不能解释为什么。:)

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

<UIView: 0x376620; frame = (0 0; 320 50); autoresize = RM+BM;
 layer = <CALayer: 0x376720>>
如果我们随后切换回第一个状态,并再次返回与节标题相同的视图,我们会在指定时间看到一些碎片:

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

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

我把它放在答案部分,因为它有助于(部分?)解释我所看到的。这还不能解释为什么。:)

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

<UIView: 0x376620; frame = (0 0; 320 50); autoresize = RM+BM;
 layer = <CALayer: 0x376720>>
如果我们随后切换回第一个状态,并再次返回与节标题相同的视图,我们会在指定时间看到一些碎片:

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

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

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

过了一段时间,我产生了一个想法,那就是一切都是错误的。在table view cells方法的外观中,我删除了如下条件子句,一切正常:
    //if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];    
    //}