这个问题是真正要解决的 PITA。有效的 API 在 iOS7 中已被弃用,或者 iOS7 替换 API 已损坏,这无济于事。呸!
您的解决方案很好,但是它使用了已弃用的 API ( sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:
),并且封装得不是很好 - 您需要将此代码复制到您想要此行为的任何单元格或视图中。从好的方面来说,它相当有效!一个错误可能是当您进行计算时标签尚未布局,但您根据其宽度执行计算。
我建议您将此行为封装在 UILabel 子类中。通过将尺寸计算放在覆盖的intrinsicContentSize
方法中,标签将自动调整尺寸。我编写了以下内容,其中包含将在 iOS6 上执行的代码,以及我的版本,使用适用于 iOS7 或更高版本的非弃用 API:
@implementation TSAutoHeightLabel
- (CGSize) intrinsicContentSize
{
NSAssert( self.baselineAdjustment == UIBaselineAdjustmentAlignCenters, @"Please ensure you are using UIBaselineAdjustmentAlignCenters!" );
NSAssert( self.numberOfLines == 1, @"This is only for single-line labels!" );
CGSize intrinsicContentSize;
if ( [self.text respondsToSelector: @selector( boundingRectWithSize:options:attributes:context: )] )
{
NSStringDrawingContext* context = [NSStringDrawingContext new];
context.minimumScaleFactor = self.minimumScaleFactor;
CGSize inaccurateSize = [self.text boundingRectWithSize: CGSizeMake( self.bounds.size.width, CGFLOAT_MAX )
options: NSStringDrawingUsesLineFragmentOrigin
attributes: @{ NSFontAttributeName : self.font }
context: context].size;
CGSize accurateSize = [self.text sizeWithAttributes: @{ NSFontAttributeName : [UIFont fontWithName: self.font.fontName size: 12.0] } ];
CGFloat accurateHeight = accurateSize.height * inaccurateSize.width / accurateSize.width;
intrinsicContentSize = CGSizeMake( inaccurateSize.width, accurateHeight);
}
else
{
CGFloat actualFontSize;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
[self.text sizeWithFont: self.font
minFontSize: self.minimumFontSize
actualFontSize: &actualFontSize
forWidth: self.frame.size.width
lineBreakMode: NSLineBreakByTruncatingTail];
#pragma GCC diagnostic pop
CGRect lineBox = CTFontGetBoundingBox((__bridge CTFontRef)([UIFont fontWithName: self.font.fontName size: actualFontSize]));
intrinsicContentSize = lineBox.size;
}
return intrinsicContentSize;
}
@end
这个实现并不完美。我必须确保使用baselineAdjustment == UIBaselineAdjustmentAlignCenters,而且我不能100% 确定我理解为什么。而且我对必须跳过以获得准确的文本高度的箍不满意。我的计算产生的结果和你的计算结果之间也存在一些像素差异。随意使用它并根据需要进行调整:)
boundingRectWithSize:options:attributes:context
API 对我来说似乎很糟糕。虽然它(大部分!)正确地将文本限制为输入大小,但它没有计算正确的高度!它返回的高度基于所提供字体的行高,即使正在缩放。我的猜测是这就是为什么UILabel
默认情况下没有这种行为?我的解决方法是计算高度和宽度都准确的不受约束的大小,然后使用受约束和不受约束的宽度之间的比率来计算受约束大小的准确高度。什么皮塔饼。Apple 开发论坛和 SO 上有很多抱怨指出这个 API 有很多这样的问题。