添加单元格并使用UITableView滚动时出现图形故障

时间:2010-04-27 15:46:32

标签: ios objective-c iphone uitableview cocoa-touch

我正在使用UITableView来显示一系列计算的结果。当用户点击“计算”时,我将最新结果添加到屏幕上。当我添加一个新单元格时,UITableViewCell对象被添加到一个数组(由tableView:cellForRowAtIndexPath:索引),然后我使用以下代码将这个新行添加到屏幕上显示的内容:

[thisView beginUpdates];
[thisView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation: UITableViewRowAnimationFade];
[thisView endUpdates];

这会导致显示新单元格。但是,我想立即向下滚动屏幕,以便新单元格是屏幕上最下面的单元格。我使用以下代码:

[thisView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

几乎效果很好。但是,第一次添加和滚动单元格时,它只会在消失前短暂显示在屏幕上。视图向下滚动到正确的位置,但单元格不在那里。手动滚动视图直到这个不可见的新单元格的位置在屏幕外,然后再返回,导致单元格出现 - 之后它表现正常。这仅在第一次添加单元格时发生;后续细胞没有这个问题。无论scrollToRowAtIndexPathinsertRowsAtIndexPath动画设置的组合如何,都会发生这种情况。

修改 我现在开始在桌子的倒数第二个位置插入单元格,而不是结尾,问题仍然存在 - 当第一次插入时,一个单元格是“不可见的”,直到它离开并返回再次。可能导致这种情况的原因,以及如何在将单元格添加到表格后立即强制绘制单元格?

4 个答案:

答案 0 :(得分:5)

您遇到问题是因为更新表而不更新支持它的数据模型。表实际上并不知道它们有多少行,也不知道要显示的单元格。它们依赖于数据源和委托来告诉他们这些事情。您的设计希望表本身能够跟踪它们。

insertRowsAtIndexPaths:旨在用于移动表周围的现有行,而不是用于添加全新的逻辑行。当您插入一个全新的单元格时,tableview会丢失它实际拥有的行数。

在显示新行之前,您应该做的第一件事是更新返回的值:

– numberOfSectionsInTableView:
– tableView:numberOfRowsInSection:

...反映新行的添加。这将使表格能够理解它有多大。

然后,您需要更新cellForRowAtIndexPath:以返回添加的行的正确单元格。然后你需要重新加载表。

完成后,您应该能够将tableview滚动到最后并正确显示单元格。

关于表格要记住的重要一点是它们是愚蠢的。表本身不包含数据,不知道它有多少部分和行或行和部分的顺序。关于数据,部分,行,单元格和单元格内容的所有逻辑来自数据源和/或代表。当您想要更改表时,实际上是更改了数据源和/或委托,然后表将自动反映这些更改。

编辑:

重新阅读父级后,我看到您将 实际UITableViewCell对象 放入数据数组中,并且每行都有一个单元格。

这不是表格视图的工作方式,而且最多不会超过几十行

表视图旨在成为一种幻觉,允许您显示具有任意高数字或行的lOGICAL表。为此,它仅保留足够的UITableViewCell对象以覆盖UI中的可视显示区域。默认单元格高度为44像素,这意味着tableview一次不会超过9个单元格对象。

表视图不是占用内存保存未显示的单元格,而是让代理将已滚动离开屏幕的单元格出列,使用另一个LOGICAL行的数据重新填充它,然后将其显示在新位置。这是在cellForRowAtIndexPath:

中完成的

你真的需要从这里开始你的设计。您的数据需要与用户界面对象分开。你不希望任何时候有更多的细胞存活,而不是绝对必要,因为你的记忆使用会膨胀,你的反应时间也会降低。您当前的问题是这种不寻常设计的结果。

完成后,您可以添加上面列出的结果行。

答案 1 :(得分:1)

尝试通过NSTimer或performSelector:withDelay:在单元格更新后滚动一些时移。它可以帮助解决我认为需要做更多工作的所有问题。

答案 2 :(得分:1)

可能会导致故障,因为UITableView认为自己是正在显示的任何UITableViewCell个实例的所有者,并根据需要重新使用它们。该过程的一部分是在单元格上调用prepareForReuse。由于您将单元格保留在数组中,因此不希望它们重复使用。尝试在prepareForReuse课程中实施空UITableViewCell。或者只是在苹果推荐的tableView:cellForRowAtIndexPath:中动态创建单元格。

答案 3 :(得分:0)

我使用Skie建议以下列方式避免此问题:

添加行后立即:

[self performSelector:@selector(scrollToDesiredArea:) withObject:newIndexPath afterDelay:0.4f];

这称为以下内容:

-(void)scrollToDesiredArea:(NSIndexPath *)indexPath{
     UITableView *thisView = (UITableView*)self.view;
     [thisView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

0.4秒的延迟似乎足以避免故障;任何更少,它仍然发生。不过,在iPhone硬件的不同型号上可能会有所不同 - 我只在模拟器上测试过。