gpt4 book ai didi

ios - 删除 UITableView 的部分后标题 View 的框架永远改变了

转载 作者:可可西里 更新时间:2023-11-01 04:44:18 25 4
gpt4 key购买 nike

我正在重用标题,将它们保存在字典中,其中节号是键,标题 View 是值。

在我删除一个部分并重新加载另一个部分后,只有这些部分的标题 View “消失”了。经过一番搜索,我发现这些标题 View 的框架已更改。 Frame.X使用 UITableViewRowAnimationRight 删除的部分的标题 View 按屏幕宽度 (320) 向右移动,以及用 UITableViewRowAnimationAutomatic 重新加载的那个由 Y 转移.

主要的问题和困惑来自于我无法更改这些框架!好吧,它们一开始会发生变化,但在视觉上和在 viewForHeaderInSection: 的另一个调用中没有任何变化。帧再次移动。

这是我的做法:

假设我们有 3 个部分,每个部分的数据位于一个数组 _first 中, _second_third .通过按钮的触摸我们调用handleTouchUp: . (_second保持不变)

- (void) handleTouchUp: (UIButton *)sender
{
if ([_first count] == 0) {
sectionCount = 3;
_first = [NSMutableArray arrayWithObjects: @"First 1", @"First 2", nil];
_third = [NSMutableArray arrayWithObjects: @"Third 1", @"Third 2", @"Third 3", @"Third 4", @"Third 5", nil];
[tableView reloadData];
} else {
sectionCount = 2;
[_first removeAllObjects];
_third = [NSMutableArray arrayWithObjects: @"First 1", @"First 2", @"Third 1", @"Third 2",
@"Third 3", @"Third 4", @"Third 5", nil];
[tableView beginUpdates];
[tableView deleteSections: [NSIndexSet indexSetWithIndex: 0] withRowAnimation:UITableViewRowAnimationRight];
[tableView reloadSections: [NSIndexSet indexSetWithIndex: 2] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
}
}


- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
NSNumber *key = [NSNumber numberWithInteger: section];
UIView *header = [_headers objectForKey: key];
if (header) {

} else {
header = [[UIView alloc] init];
switch (section) {
//Doing something with header here (e.g. set background color)
}
[_headers setObject:header forKey: key];
}

[header setFrame: CGRectMake(0, 0, 320, 25)];

return header;
}

Here is full code of ViewController.mtest project

更新:项目中可能还有其他一些错误,但这并不重要——它是测试项目。唯一重要的问题是无效的标题 View 。删除无效 View 并创建新 View 不是解决方案——它扼杀了重用标题 View 的意义。

最佳答案

我在您的项目中发现了几个错误,这些错误实际上导致了一些崩溃,我相信它们也对您在应用程序中看到的标题 View 错误负责。在我修复这些问题之后,应用程序对我来说似乎可以正常运行。

这是您项目的更新版本:https://bitbucket.org/reydan/tableheaderviews

我尽量保持它与您最初的项目相似,但我不得不进行一些更改。如果您认为它不符合您想要的功能,请发表评论,我会更新(这是我推断该项目应该表现的样子)下面解释的所有更改也可以在此更新的项目中看到。

我发现的问题与以下事实有关:如果您从 TableView 中删除一个部分,则它之后的所有部分的索引都会更改(-1)。这是正常的,因为部分索引实际上是一个索引,而不是分配给每个部分的唯一键。

删除第一部分后,第三部分现在有索引 = 1,并且 TableView 委托(delegate)方法错误地读取数据(包括标题 View ),因为您的所有内容都基于部分索引。

为了解决这个问题,我更改了 header View 缓存以使用数据数组作为键(_first、_second 或 _third)。为了使这更容易,我创建了一个可以从多个地方调用的方法,并根据节索引和当前节数返回正确的数据数组:

- (NSArray*)dataArrayForSection:(NSInteger)section
{
if (sectionCount == 3)
{
switch (section)
{
case 0: return _first;
case 1: return _second;
case 2: return _third;
}
}
else
{
switch (section)
{
case 0: return _second;
case 1: return _third;
}
}

return nil;
}

现在 header 缓存使用数据数组作为键,在 handleTouchUp 方法中重新分配数组时删除 header 条目很重要。

- (void) handleTouchUp: (UIButton *)sender
{
NSLog(@"Touched!");
if ([_first count] == 0)
{
sectionCount = 3;

// **INSERTED** Removes the cache for the _first and _third keys because you are recreating the arrays again,
// and so you are losing the initial key. Not doing this, results in a memory leak
[_headers removeObjectForKey:_first];
[_headers removeObjectForKey:_third];

_first = [NSMutableArray arrayWithObjects: @"First 1", @"First 2", nil];
_third = [NSMutableArray arrayWithObjects: @"Third 1", @"Third 2", @"Third 3", @"Third 4", @"Third 5", nil];

[tableView reloadData];
// [tableView beginUpdates];
// [tableView reloadSections: [NSIndexSet indexSetWithIndex: 0] withRowAnimation:UITableViewRowAnimationRight];
// [tableView reloadSections: [NSIndexSet indexSetWithIndex: 2] withRowAnimation:UITableViewRowAnimationAutomatic];
// [tableView endUpdates];
}
else

我改进的另一件事是重用表格 View 单元格。您应该始终尝试并重用现有的 UITableViewCells(除了少数异常(exception))。 cellForRowAtIndexPath 现在看起来像这样:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray* dataarray = [self dataArrayForSection:indexPath.section];


UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"my_text_cell"];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"my_text_cell"];


if (dataarray == nil)
cell.textLabel.text = @"default";
else
cell.textLabel.text = [dataarray objectAtIndex:indexPath.row];


return cell;
}

如果您有任何问题,请发表评论。

编辑

我尝试按照您的要求更新我的测试项目,以保持缓存完好无损,并且我确实能够重现该错误 - 在删除/重新加载动画之后,最后一部分的标题不可见。

我发现iOS选择的Automatic reload动画是Fade动画。这会导致标题 View 淡出。我通过在应用程序中添加另一个按钮来测试这一点,该按钮为所有缓存的标题 View 设置 alpha=1 。重新加载动画后,我按下此按钮,标题 View 正确显示。

我尝试使用其他动画,但效果不佳。

最后,我认为 Apple 不建议缓存标题 View 。在文档中,从 iOS 6.0 开始,有一种解决此问题的新方法。它的行为类似于出列单元格,但用于页眉/页脚 View
- (id)dequeueReusableHeaderFooterViewWithIdentifier:(NSString *)identifier

因此,如果您的目标是 iOS 6.0+,那么您可以使用它来代替手动缓存 header 。否则,我找到的解决方案是仅从缓存中删除已删除和重新加载部分(_first 和 _third)的标题 View 。

我更新了项目以在刷新时仅删除最后一节标题

关于ios - 删除 UITableView 的部分后标题 View 的框架永远改变了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16979150/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com