问题描述
所以我尝试使用内置的 UITableViewCell 样式 - 特别是 UITableViewCellStyleSubtitle - 带有(单)行 textLabel 但 multiline detailTextLabel.但是(自动)计算的单元格高度始终太短,并且似乎忽略了超过 1 行的细节.
So I'm trying to use the built-in UITableViewCell styles - specifically UITableViewCellStyleSubtitle - with a (single) line textLabel but multiline detailTextLabel. But the (auto) calculated cell height is consistently too short, and appears to ignore that there is more than 1 line of detail.
我尝试使用 numberOfLines=0、estimatedRowHeight、UITableViewAutomaticDimension、preferredMaxWidthLayout 等,但在所有排列中,行为 - 实际上对于 所有 UITableViewCell 样式 - 是否出现 UITableViewAutomaticDimension 单元格高度计算将正确解释多行 textLabel(耶!),但错误地假设 detailTextlabel 最多为单行(不!).因此,具有多行 detailTextLabel 的单元格太短,因此单元格内容会溢出单元格的顶部和底部.
I've tried using numberOfLines=0, estimatedRowHeight, UITableViewAutomaticDimension, preferredMaxWidthLayout, etc, but in all the permutations the behavior - indeed for all the UITableViewCell styles - is it appears the UITableViewAutomaticDimension cell height calculation will correctly account for a multiline textLabel (yay!), but incorrectly assumes the detailTextlabel is at most single line (nay!). Consequently, cells with a multiline detailTextLabel are too short, and hence the cell content spills over the top and bottom of the cell.
我已在 GitHub 此处 上发布了一个快速测试应用程序来显示此行为.添加额外的文本行很好——所有的单元格样式都会适当地增加高度以适应——但是添加额外的细节行不会改变单元格的高度,并且很快就会导致内容溢出;文本+细节本身布局正确,并在单元格中间正确居中(因此从这个意义上讲 layoutSubviews 工作正常),但整体单元格高度本身没有变化.
I've posted a quick test app showing this behavior on GitHub here. Adding additional lines of text is fine - all the cell styles appropriately increase in height to accommodate - but adding additional lines of detail does nothing to change the cell height, and quickly causes the content to spill over; the text+detail are themselves laid out correctly, and together centered correctly over the middle of the cell (so in that sense layoutSubviews is working correctly), but the overall cell height itself is unchanged.
看起来几乎没有真正的顶部 &cell.contentView 和标签之间的底部约束,而是直接从(可能是多行)textLabel 和(仅单行)detailTextLabel 的高度计算单元格高度,然后所有内容都集中在单元格...再次,多行 textLabel 很好,我在 textLabel 和 detailTextLabel 之间没有做任何不同,但只有前者(正确)调整单元格高度.
It almost seems like there are no actual top & bottom constraints between the cell.contentView and the labels, and instead the cell height is being calculated directly from the height of the (possibly multi-line) textLabel and (only single-line) detailTextLabel, and then everything is centered over the middle of the cell... Again, multiline textLabel is fine, and I'm doing nothing different between the textLabel and detailTextLabel, but only the former (correctly) adjusts the cell height.
所以我的问题是,如果可以使用内置的 UITableViewCell 样式可靠地显示 multiline detailTextLabels,还是根本不可能,您需要而是创建一个自定义子类?[或者,几乎等效地,无需在子类中覆盖 layoutSubviews 并手动重新连接所有约束].
So my question is, if it is possible to use the built-in UITableViewCell styles to reliably display multiline detailTextLabels, or is it simply not possible and you need to create a custom subclass instead? [or, almost equivalently, without having to override layoutSubviews in a subclass and rewire all the constraints manually].
[2016 年 5 月 4 日] 结论:从 iOS9 开始,多行 detailTextLabels 在 UITableViewAutomaticDimension 中无法正常工作;单元格总是太短,文本/细节会溢出顶部和底部.您必须自己手动计算正确的单元格高度,或者创建和布局您自己的等效自定义 UITableViewCell 子类,或者(请参阅下面的答案)子类 UITableViewCell 并修复 systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
以返回正确的高度 [推荐]
[4 May 2016] Conclusion: as of iOS9 multi-line detailTextLabels dont work as expected with UITableViewAutomaticDimension; the cell will be consistently too short and the text/detail will spill over the top and bottom. Either you must manually compute the correct cell height yourself, or create and layout your own equivalent custom UITableViewCell subclass, or (see my answer below) subclass UITableViewCell and fix systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
to return the correct height [recommended]
推荐答案
进一步调查(见UITableViewCellTest) 表示当 UITableViewAutomaticDimension 启用时,系统调用 -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
来计算单元格高度,并且这几乎忽略了其中 detailTextLabel 的高度计算(错误!?).结果,对于 UITableViewCellStyleSubtitle,单元格高度总是太短 [单行 detailTextLabel 可能不会完全溢出单元格,但这仅仅是因为现有的顶部和底部边距],对于 UITableViewCellStyleValue1 或 UITableViewCellStyleValue2,只要 detailTextLabel 高于(例如更多行),高度就会太短文本标签.这对于没有 detailTextLabel 的 UITableViewCellStyleDefault 来说都是一个有争议的问题.
Further investigations (see UITableViewCellTest) indicate that when UITableViewAutomaticDimension is enabled the system calls -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
to calculate the cell height, and that this pretty much ignores the height of the detailTextLabel in its computation (bug !?). As a result, for UITableViewCellStyleSubtitle the cell height is always going to be too short [a single-line detailTextLabel may not quite spill over the cell, but that's only because of the existing top and bottom margins], and for UITableViewCellStyleValue1 or UITableViewCellStyleValue2 the height will be too short whenever the detailTextLabel is taller (eg more lines) than the textLabel. This is all a moot point for UITableViewCellStyleDefault which has no detailTextLabel.
我的解决方案是子类化和修复:
My solution was to subclass and fix with:
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize
withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority
verticalFittingPriority:(UILayoutPriority)verticalFittingPriority
{
// Bug finally fixed in iOS 11
if ([UIDevice.currentDevice.systemVersion compare:@"11" options:NSNumericSearch] != NSOrderedAscending) {
return [super systemLayoutSizeFittingSize:targetSize
withHorizontalFittingPriority:horizontalFittingPriority
verticalFittingPriority:verticalFittingPriority];
}
[self layoutIfNeeded];
CGSize size = [super systemLayoutSizeFittingSize:targetSize
withHorizontalFittingPriority:horizontalFittingPriority
verticalFittingPriority:verticalFittingPriority];
CGFloat detailHeight = CGRectGetHeight(self.detailTextLabel.frame);
if (detailHeight) { // if no detailTextLabel (eg style = Default) then no adjustment necessary
// Determine UITableViewCellStyle by looking at textLabel vs detailTextLabel layout
if (CGRectGetMinX(self.detailTextLabel.frame) > CGRectGetMinX(self.textLabel.frame)) { // style = Value1 or Value2
CGFloat textHeight = CGRectGetHeight(self.textLabel.frame);
// If detailTextLabel taller than textLabel then add difference to cell height
if (detailHeight > textHeight) size.height += detailHeight - textHeight;
} else { // style = Subtitle, so always add subtitle height
size.height += detailHeight;
}
}
return size;
}
在视图控制器中:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = 44.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
您可以从这里提取完整的子类:MultilineTableViewCell
You can pull the full subclass from here: MultilineTableViewCell
到目前为止,这个修复似乎运行良好,并且让我成功地使用了带有 multiline 文本和详细信息的内置 UITableViewCellStyles,在支持动态类型的自动调整单元格中.这避免了在 tableView:heightForRowAtIndexPath:
中手动计算所需单元格高度或必须创建自定义单元格布局的麻烦(和混乱).
So far this fix appears to work well, and has let me successfully use the built-in UITableViewCellStyles with multiline text and details, in self-sizing cells with dynamic type support. This avoids the trouble (and mess) of manually computing the desired cell heights in tableView:heightForRowAtIndexPath:
, or having to create custom cell layouts.
[(部分)在 iOS11 中修复]
Apple终于在 iOS11 中修复了这个错误(但显然仅适用于 UITableViewCellStyleSubtitle).我已经更新了我的解决方案,只对 11 之前的设备应用必要的修正(否则你的单元格顶部和底部会出现额外的空间!).
Apple finally fixed this bug in iOS11 (but apparantly only for UITableViewCellStyleSubtitle). I've updated my solution to only apply the necessary correction to pre-11 devices (otherwise you'll end up with extra space top and bottom of your cell!).
这篇关于自动布局在计算 UITableViewCell 高度时忽略多行 detailTextLabel(所有样式)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!