为什么heightForRowAtIndexPath:来自cellForRowAtIndexPath:?

时间:2014-02-04 01:40:48

标签: ios cocoa-touch uitableview

几乎每次我为客户编写应用程序时,我都必须实现某种“黑客”以使UITableViewCell动态变为正确的高度。根据细胞的含量,这可能会有所不同。

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

在过去的两年里,我可能已经编写并重写了这段代码20次。 Apple为什么按此顺序实施它?配置单元格会更加直接,然后在cellForRowAtIndexPath:heightForRowAtIndexPath:之后不久设置高度。

现有订单是否有充分理由?有没有更好的方法来处理它?<​​/ p>

2 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:5)

实际上,在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:)。