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

Posted

技术标签:

【中文标题】似乎无法为 UILabel 计算正确的 NSAttributedString 行高【英文标题】:Can't seem to calculate correct line-height of NSAttributedString for a UILabel 【发布时间】:2014-04-07 15:19:47 【问题描述】:

阅读this article from objc.io后,我正在使用NSAttributedString'sboundingRectWithSize:options:context:方法计算某些文本的预期高度

+(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: 的一个潜在错误。我想出了一个解决方法:创建一个虚拟UILabel,赋予它与表格视图单元格中的UILabel 相同的属性(numberOfLines 等),然后使用sizeThatFits: 计算大小。可以肯定的是,这是一个 hack - 但它充分解决了我的问题。不过,我希望它更优雅!

【问题讨论】:

【参考方案1】:

我在尝试计算 UITextView 的属性文本大小时遇到​​了同样的效果。我遇到了this answer to another question。

诀窍是使用NSLayoutManager's usedRectForTextContainer:。巧妙的是,此方法不需要与 UITextView 结合使用。这意味着您可以在 mainThread 之外使用它,这是预先计算 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。我对整个编程有点陌生,所以如果我的代码可以优化,请告诉我。

【讨论】:

【参考方案2】:

我想,你可能没有设置preferredMaxLayoutWidth

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

【讨论】:

以上是关于似乎无法为 UILabel 计算正确的 NSAttributedString 行高的主要内容,如果未能解决你的问题,请参考以下文章

自定义安装的字体未在 UILabel 中正确显示

UITableViewCell 计算正确的高度,但 UILabel 不换行

为自动布局设置数字 UILabel 以正确计算内在内容大小

UICollectionViewCell 中的 UILabel 有时无法正确调整大小

ScrollView中的UILabel sizeToFit

为啥我在 UITableCellView 中的 UIView 中的 UILabel 在正确的数据库调用后没有更新(似乎与单元重用有关)?