Calc NSAttributedString size correctly with NSLayoutManager

Dec 16, 2018 • 预计阅读时间 1 分钟

Some code like this:

NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"lvv" attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:30]}];
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attrString];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(INFINITY, INFINITY)];
[layoutManager addTextContainer:textContainer];

CGRect usedRect = [layoutManager usedRectForTextContainer:textContainer];
NSLog(@"usedRect:%@", NSStringFromCGRect(usedRect));

result is CGRectZero:

usedRect:{{0, 0}, {0, 0}}

Why?

Because glyph generation, layout and font fallback not have happened yet.

Just adjust code simply:

NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"lvv" attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:30]}];

NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(INFINITY, INFINITY)];
[layoutManager addTextContainer:textContainer];

// add layout at the last
NSTextStorage *textStorage = [[NSTextStorage alloc] init];
[textStorage addLayoutManager:layoutManager];
// set string after add layout
[textStorage setAttributedString:attrString];

CGRect usedRect = [layoutManager usedRectForTextContainer:textContainer];
NSLog(@"usedRect:%@", NSStringFromCGRect(usedRect));

the result is correct:

usedRect:{{0, 0}, {46.1962890625, 35.80078125}}

BTW:

Apple suggest call glyphRangeForTextContainer before usedRectForTextContainer , because the layout manager performs layout lazily.

Calculating Text Height

BUT, no effect.

版权声明:如果转发请带上本文链接和注明来源。

lvv.me

iOS/macOS Developer

Change toolchain for Xcode

Debug WebKit with Xcode on iOS simulator