为什么heightForRowAtIndexPath:来自cellForRowAtIndexPath:?

cen*_*eee 7 cocoa-touch uitableview ios

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

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

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

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

zap*_*aph 8

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

  • 不是猜测.事实. (3认同)

mat*_*att 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];
}
Run Code Online (Sandbox Code Playgroud)

您提供了估计的高度,因此不会事先要求所有高度.在该行实际出现在界面之前,系统会要求您输入一个高度,因为它最初显示或者因为您或用户滚动显示它.

注意另外,请注意,如果您使用dequeueReusableCellWithIdentifier:forIndexPath:的单元格已经具有正确的最终高度.这就是这种方法的重点(与早先的相反dequeueReusableCellWithIdentifier:).