UITableViewCell框架高度不匹配tableView:heightForRowAtIndexPath:

时间:2012-08-10 09:12:18

标签: ios objective-c uitableview reusability heightforrowatindexpath

我正在构建一个具有可变高度自定义表格单元格的UITableView,它们的高度由包含的多行UILabel的大小决定。我已将tableView:heightForRowAtIndexPath:委托方法连接起来并使用sizeWithFont:constrainedToSize:正确计算最终高度。

我遇到了一个奇怪的问题:到调用数据源方法tableView:cellForRowAtIndexPath:时,如上所述已经确定了正确的每行高度,但是单元格的框架与高度。相反,单元格的frame.size.height属性是表格视图的默认单元格高度(86 px,因为我在Interface Builder中设置它,当包含的UILabel只有一行文本时正确的高度),而不是tableView:heightForRowAtIndexPath:确定的索引路径正确的高度。

我使用dequeuing在cellForRowAtIndexPath:中生成单元格,即

// Using storyboards, this never returns nil, no need to check for it
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:@"SomeIdentifier"];
NSLog(@"%f", cell.frame.size.height); // 86, not correct if the cell contains a multi-line UILabel

然而,似乎无论iOS在幕后做什么,出列都不是设置单元格的frame属性来匹配计算出的高度。这本身就不那么令人惊讶,因为细胞实例而不是它们的几何体而引起了人们的关注。但是,单元格正确呈现,因此高度属性设置为某处,但它发生在cellForRowAtIndexPath:之后。

所以:当我最初填充表格视图时,cell.frame.size.height对于所有单元格都是86,因为当我向下滚动列表时它们首次出现。由于在显示之前每行的第一个cellForRowAtIndexPath:之后的某个时间设置了正确的几何,所以当我向上滚动时,高度属性对于重新使用后返回视图的每个单元格都是正确的。

在此之后,我可以随意来回滚动表格视图,并且从该点开始,每个单元格的高度属性都保持正确。

在任何基于出队的重用发生之前,第一次获得正确的单元格高度的正确方法是什么?我需要这个来重新定位表格单元格的子视图。我是否需要在heightForRowAtIndexPath:中手动调用cellForRowAtIndexPath:,然后手动设置新创建的CustomCell实例的帧以匹配该高度?这似乎是多余的,我需要创建一种机制来检测第一次使用错误的帧高度创建单元格的时间,以及稍后使用正确的帧高度进行出列以避免此冗余的情况。

所以,如果有人能够了解这背后的逻辑,我会很感激。

3 个答案:

答案 0 :(得分:6)

正如Flexo所建议的那样,自己回答这个问题显然比在问题中添加编辑更好。所以,这是以前的编辑作为答案:


没关系,我应该更好地阅读文档。我可以在tableView:willDisplayCell:forRowAtIndexPath:的{​​{1}}方法中获得正确的框架,因此这是进行子视图自定义的正确位置,该子视图自定义依赖于正在设置的正确框架,而不是UITableViewDelegate

有趣的是,文档说这个,但是:

  

cellForRowAtIndexPath:返回后,表格视图仅设置delegatealpha属性,然后仅在行滑入或滑出时设置动画。

...因为调用此委托方法时正确的帧已存在。但无论如何,问题已经解决了。

答案 1 :(得分:0)

不要忘记单元格是UIView,因此覆盖layoutSubviews也是获取正确框架和调整子视图大小/位置的有效方法。别忘了给[super layoutSubviews]打电话。

答案 2 :(得分:0)

我发现最简单的方法就是在对单元格进行任何设置之前调用cell.layoutIfNeeded()。这样可以确保计算所有布局约束并设置框架。