7

Following the official docs, I created this function to calculate text height.

func calculateTextHeight(myString: String, myWidth: CGFloat, myFont: UIFont) -> CGFloat { let textStorage = NSTextStorage(string: myString) let textContainer = NSTextContainer(size: CGSize(width: myWidth, height: CGFloat.max)) let layoutManager = NSLayoutManager() layoutManager.addTextContainer(textContainer) textStorage.addLayoutManager(layoutManager) textStorage.addAttribute(NSFontAttributeName, value: myFont, range: NSMakeRange(0, textStorage.length)) textContainer.lineFragmentPadding = 0 textContainer.lineBreakMode = .ByWordWrapping layoutManager.glyphRangeForTextContainer(textContainer) return layoutManager.usedRectForTextContainer(textContainer).size.height } 

But the calculated height is wrong when the text contains an emoji.

var s = "ABCDE 12345" print(calculateTextHeight(s, myWidth: 500, myFont: UIFont.systemFontOfSize(14))) // prints 16.7 (correct) s = "ABCDE 12345 💩" print(calculateTextHeight(s, myWidth: 500, myFont: UIFont.systemFontOfSize(14))) // prints 22.9 (should be 16.7) 

Is this a bug? How can I fix this?

1
  • Though this's an question but it helped me. Thanks Commented Sep 1, 2016 at 8:34

3 Answers 3

3

This worked for me when text contains emojis. For NSAttributedString strings:

extension NSAttributedString { func sizeOfString(constrainedToWidth width: Double) -> CGSize { let framesetter = CTFramesetterCreateWithAttributedString(self) return CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRange(location: 0, length: 0), nil, CGSize(width: width, height: .greatestFiniteMagnitude), nil) } } 

For String:

extension String { func sizeOfString(constrainedToWidth width: Double, font: UIFont) -> CGSize { let attributes = [NSAttributedString.Key.font : font] let attString = NSAttributedString(string: self, attributes: attributes) let framesetter = CTFramesetterCreateWithAttributedString(attString) return CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRange(location: 0, length: 0), nil, CGSize(width: width, height: .greatestFiniteMagnitude), nil) } } 
Sign up to request clarification or add additional context in comments.

Comments

0

I used an alternate method to calculate text height. This works with emojis.

static func calculateStringHeight(str: String, maxWidth: CGFloat, font: UIFont) -> CGFloat { return str.boundingRectWithSize(CGSizeMake(maxWidth, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).height } 

Comments

-2

I do not think it is a bug. Emoji take up more space to be displayed.

I believe this will make a difference only if the number of emoji in your text is too large. If you try the code below, i think that the result will be the same.

s = "ABCDE 12345 💩💩💩💩💩💩💩" print(calculateTextHeight(s, myWidth: 500, myFont: UIFont.systemFontOfSize(14))) // prints 22.9 

If you want to eliminate the emoji, you can remove them from the original text before doing the height calculation. In this case, you need to scan the original text by replacing all emoji by other character, and then call the height calculation.

2 Comments

Removing emojis before doing height calculation defeats the purpose of the function since the width changes as well.
Instead remove then, replace each one for any caracter. I guess that the height will be very close.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.