问题
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