为什么heightForRowAtIndexPath:在cellForRowAtIndexPath之前:?

几乎每次我为客户写一个应用程序时,我都必须实现某种“黑客”才能让UITableViewCelldynamic地变成正确的高度。 根据细胞的内容,这可能会有所不同。

我通常最终运行通过格式化单元格的代码两次,一次在heightForRowAtIndexPath:然后在cellForRowAtIndexPath:再次运行。 然后,我使用数组或字典来存储高度或格式化的单元格对象。

我可能在过去的2年里写了20次这个代码。 苹果为什么按这个顺序执行它? 这将是更简单的configuration单元格,然后设置高度或者在cellForRowAtIndexPath:heightForRowAtIndexPath:heightForRowAtIndexPath:

现有订单有充分的理由吗? 有更好的方法来处理它吗?

最佳猜测: UITableView需要知道所有单元格的总高度,以便它可以知道滚动条的百分比和其他需求。

实际上,在iOS 7中,它不必这样工作。 您现在可以为行设置估计的高度,并仅在实际需要该行时计算每行的实际高度。 (我想这正是因为人们对你的投诉是一样的:“为什么我要这样做两次?”)

因此,您可以推迟高度计算,然后在第一次出现该行时对其进行记忆(这适用于简单的单节表,但是如果您有多个节,则很容易调整):

 - (void)viewDidLoad { [super viewDidLoad]; // create empty "sparse array" of heights, for later NSMutableArray* heights = [NSMutableArray new]; for (int i = 0; i < self.modeldata.count; i++) [heights addObject: [NSNull null]]; self.heights = heights; self.tableView.estimatedRowHeight = 40; // new iOS 7 feature } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { int ix = indexPath.row; if ([NSNull null] == self.heights[ix]) { h = // calculate _real_ height here, on demand self.heights[ix] = @(h); } return [self.heights[ix] floatValue]; } 

你提供了一个估计的高度,所以事先要求所有的高度。 只有在该行实际出现在界面中之前,才要求您提供一个高度,要么是因为它最初显示,要么是因为您或用户滚动显示。

注意另外,请注意,如果您使用dequeueReusableCellWithIdentifier:forIndexPath:您获得的单元格已经具有正确的最终高度 。 这是这个方法的全部重点(与之前的仅仅是dequeueReusableCellWithIdentifier:相反)。