Can't seem to calculate correct line-height of NSAttributedString for a UILabel

不打扰是莪最后的温柔 提交于 2019-12-24 01:39:20

问题


I'm using NSAttributedString's boundingRectWithSize:options:context: method to calculate the expected height for some text, after reading this article from 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);
}

However, when I use this method, the text doesn't actually fit inside this size - the size is consistently too short.

At first, I'd thought the issue was with emoji characters - but it seems to be happening for many tableviewcells in the app.

Update: I've talked with a few folks, and it sounds like the issue may be an underlying bug with boundingRectWithSize:options:context:. I figured out a workaround: create a dummy UILabel, give it the same attributes as the UILabel in the tableview cell (numberOfLines, etc) and then use sizeThatFits: to calculate the size. It's a hack, to be sure - but it solves my problem sufficiently. I wish it were more elegant, though!


回答1:


I came across this same effect when trying to calculate the size of attributed text for a UITextView. I ran across this answer to another question.

The trick is to use NSLayoutManager's usedRectForTextContainer:. What is neat is that this method doesn't need to be used in conjunction with a UITextView. This means that you can use it off of the mainThread, key for pre-calculation of UITableViewCell heights.

Here's how I use it:

- (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));
}

To make things easier, I created a convenience method to figure out the height for a specific width:

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

Hope this helps.


PS. I'm kind of new at this whole programming thing so if my code can be optimized please let me know.




回答2:


I think, you might not set preferredMaxLayoutWidth.

This property set constraint to the max width of a view.



来源:https://stackoverflow.com/questions/22916566/cant-seem-to-calculate-correct-line-height-of-nsattributedstring-for-a-uilabel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!