似乎无法为UILabel计算NSAttributedString的正确行高

我正在使用NSAttributedString's boundingRectWithSize:options:context:方法来计算某些文本的预期高度, 从objc.io阅读本文后

 +(CGSize)postLabelSizeForPost:(ANKPost *)post { CGFloat labelWidth = 220.0f; NSAttributedString *text = [BXTPostCell mutableAttributedStringForPost:post]; NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading; CGRect boundingRect = [text boundingRectWithSize:CGSizeMake(labelWidth, CGFLOAT_MAX) options:options context:nil]; CGFloat height = (CGFloat) (ceil(boundingRect.size.height)); return CGSizeMake(labelWidth, height); } 

但是,当我使用这种方法时,文本实际上并不适合这个大小 – 大小一直太短。

起初,我认为这个问题与表情符号有关 – 但它似乎正在应用程序中的许多tableviewcells中发生。

更新:我和一些人聊过,听起来这个问题可能是boundingRectWithSize:options:context:一个潜在错误boundingRectWithSize:options:context: . 我想出了一个解决方法:创建一个虚拟的UILabel ,给它与tableview单元格中的UILabel相同的属性( numberOfLines等),然后使用sizeThatFits:来计算大小。 这是一个黑客,当然 – 但它足以解决我的问题。 不过我希望它更优雅!

在尝试计算UITextView的属性文本大小时,我遇到了同样的效果。 我在另一个问题上遇到了这个答案 。

诀窍是使用NSLayoutManager的usedRectForTextContainer: . 什么是整洁的是这个方法不需要与UITextView一起使用。 这意味着您可以将它从mainThread,key用于预先计算UITableViewCell高度。

这是我如何使用它:

 - (CGSize)rectForAttributedString:(NSAttributedString *)string withSize:(CGSize)theSize { if (!string || CGSizeEqualToSize(theSize, CGSizeZero)) { return CGSizeZero; } // setup TextKit stack NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:theSize]; NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:string]; NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; [layoutManager addTextContainer:textContainer]; [textStorage addLayoutManager:layoutManager]; // query for size CGRect rect = [layoutManager usedRectForTextContainer:textContainer]; return CGSizeMake(ceilf(rect.size.width), ceilf(rect.size.height)); } 

为了简化操作,我创建了一种方便的方法来计算特定宽度的高度:

 - (CGFloat)textViewHeightForAttributedString:(NSAttributedString *)string withWidth:(CGFloat)width { return [self rectForAttributedString:string withSize:CGSizeMake(width, CGFLOAT_MAX)].height; } 

希望这可以帮助。


PS。 我对这整个编程问题都很陌生,所以如果我的代码可以优化,请告诉我。

我想,你可能不会设置preferredMaxLayoutWidth

此属性将约束设置为视图的最大宽度。