所以我试图使用内置的UITableViewCell样式 - 特别是UITableViewCellStyleSubtitle - 使用(单)行 textLabel 但多行 detailTextLabel 。但是(自动)计算的单元格高度始终太短,并且似乎忽略了超过1行细节。
我已经尝试过使用numberOfLines = 0,estimatedRowHeight,UITableViewAutomaticDimension,preferredMaxWidthLayout等,但在所有排列行为中 - 实际上对于所有 UITableViewCell样式 - 是否出现了UITableViewAutomaticDimension单元格高度计算将正确地考虑多行 textLabel (yay!),但错误地认为 detailTextlabel 最多是单行(nay!)。因此,具有多行detailTextLabel的单元格太短,因此单元格内容溢出单元格的顶部和底部。
我发布了一个快速测试应用,在GitHub here上显示此行为。添加额外的文本行很好 - 所有单元格样式的高度适当增加以适应 - 但添加额外的细节行不会改变单元格高度,并且很快会导致内容溢出;文本+细节本身正确布局,并且一起正确地居中在单元格的中间(因此在这种意义上,layoutSubviews正常工作),但整体单元格高度本身没有变化。
几乎看起来没有真正的顶级& cell.contentView和标签之间的底部约束,而是直接从(可能是多行)textLabel和(只有单行)detailTextLabel的高度计算单元格高度,然后所有内容都集中在中间单元格...再次,多行textLabel很好,我在textLabel和detailTextLabel之间没有任何不同,但只有前者(正确)调整单元格高度。
所以我的问题是,如果可以使用内置的UITableViewCell样式来可靠地显示多行 detailTextLabels ,或者它根本不可能而且您需要改为创建一个自定义子类? [或者,几乎等效地,不必覆盖子类中的layoutSubviews并手动重新连接所有约束]。
[2016年5月4日]结论:从iOS9开始,多行detailTextLabels无法按预期使用UITableViewAutomaticDimension;单元格将始终太短,文本/细节将溢出顶部和底部。您必须自己手动计算正确的单元格高度,或者创建和布局您自己的等效自定义UITableViewCell子类,或者(请参阅下面的答案)子类UITableViewCell并修复systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
以返回正确的高度[推荐]
答案 0 :(得分:20)
进一步调查(参见UITableViewCellTest)表明,当启用 UITableViewAutomaticDimension 时,系统调用-systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:
来计算单元格高度,这几乎忽略了高度detailTextLabel在其计算中(bug!?)。因此,对于 UITableViewCellStyleSubtitle ,单元格高度总是太短[单行 detailTextLabel 可能不会完全溢出单元格,但这仅仅是因为现有的上边距和下边距],对于 UITableViewCellStyleValue1 或 UITableViewCellStyleValue2 ,只要 detailTextLabel 更高(例如更多行),高度就会太短 textLabel 。这对于没有detailTextLabel的 UITableViewCellStyleDefault 来说都是没有实际意义的。
我的解决方案是继承并修复:
- (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
到目前为止,此修复程序似乎运行良好,并且让我成功使用内置的UITableViewCellStyles与多行文本和详细信息,在具有动态类型支持的自定义单元格中。这避免了在tableView:heightForRowAtIndexPath:
中手动计算所需单元格高度的麻烦(和混乱),或者必须创建自定义单元格布局。
[(部分)在iOS11中固定]
Apple 终于修复了iOS11中的这个错误(但仅适用于UITableViewCellStyleSubtitle)。我已经更新了我的解决方案,只对11之前的设备应用了必要的修正(否则你最终会得到额外的空间顶部和底部!)。
答案 1 :(得分:4)
@tiritea在Swift 3中的回答(再次感谢!:D)
// When UITableViewAutomaticDimension is enabled the system calls
// -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: to calculate the cell height.
// Unfortunately, it 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.
// So we override to include detailTextLabel height.
// Credit: http://stackoverflow.com/a/37016869/467588
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
self.layoutIfNeeded()
var size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority)
if let textLabel = self.textLabel, let detailTextLabel = self.detailTextLabel {
let detailHeight = detailTextLabel.frame.size.height
if detailTextLabel.frame.origin.x > textLabel.frame.origin.x { // style = Value1 or Value2
let textHeight = textLabel.frame.size.height
if (detailHeight > textHeight) {
size.height += detailHeight - textHeight
}
} else { // style = Subtitle, so always add subtitle height
size.height += detailHeight
}
}
return size
}
答案 2 :(得分:2)
Swift 3
在阅读了各种答案之后,我使用了以下方法来获取详细文本标签UITableViewAutomaticDimension问题。仅使用带有标题标签的基本样式单元格,并将文本和详细文本视图的属性字符串用于。不要忘记将tableview单元格样式从Subtitle更改为Basic。
func makeAttributedString(title: String, subtitle: String) -> NSAttributedString {
let titleAttributes = [NSFontAttributeName: UIFont.preferredFont(forTextStyle: .headline), NSForegroundColorAttributeName: UIColor.purple]
let subtitleAttributes = [NSFontAttributeName: UIFont.preferredFont(forTextStyle: .subheadline)]
let titleString = NSMutableAttributedString(string: "\(title)\n", attributes: titleAttributes)
let subtitleString = NSAttributedString(string: subtitle, attributes: subtitleAttributes)
titleString.append(subtitleString)
return titleString
}
如何在cellforrowatindexpath中使用
cell.textLabel?.attributedText = makeAttributedString(title: "Your Title", subtitle: "Your detail text label text here")
在viewdidload中添加以下行
YourTableView.estimatedRowHeight = UITableViewAutomaticDimension
YourTableView.rowHeight = UITableViewAutomaticDimension
YourTableView.setNeedsLayout()
YourTableView.layoutIfNeeded()
答案 3 :(得分:1)
根据我的经验,内置单元格不支持自动调整大小限制,我认为最好的解决方案是创建一个自定义单元格,它真的需要几分钟而你不需要覆盖layoutSubview,真的很简单。 只需将IB中单元格的类型更改为自定义,拖动标签,设置约束(在IB中),设置行数,创建子类,将IB中的单元格类更改为子类,在子类和大部分工作, 我相信你可以在网上找到很多教程。
答案 4 :(得分:1)
看起来Apple已经在iOS 11中解决了这个错误。