boundingRectWithSize for NSAttributedString returning wrong size
Looks like you weren't providing the correct options. For wrapping labels, provide at least:
CGRect paragraphRect =
[attributedText boundingRectWithSize:CGSizeMake(300.f, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
context:nil];
Note: if the original text width is under 300.f there won't be line wrapping, so make sure the bound size is correct, otherwise you will still get wrong results.
NSAttributedString boundingRect returns wrong height
I found that this solution works. Note that if you don't set the lineFragmentPadding
to 0
, it produces the same (wrong) results as boundingRect
.
extension NSAttributedString {
func sizeFittingWidth(_ w: CGFloat) -> CGSize {
let textStorage = NSTextStorage(attributedString: self)
let size = CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)
let boundingRect = CGRect(origin: .zero, size: size)
let textContainer = NSTextContainer(size: size)
textContainer.lineFragmentPadding = 0
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
layoutManager.glyphRange(forBoundingRect: boundingRect, in: textContainer)
let rect = layoutManager.usedRect(for: textContainer)
return rect.integral.size
}
}
NSAttributedString size() method returns incorrect width
For future reference: I figured out the issue. When using attributedTitle
, it's important to specify the font of the button, so that attributedString.size()
can calculate the necessary width correctly. I assumed that by default, calculations are based on the default font for NSButton
but apparently that was incorrect. See my commit for more details.
NSString boundingRectWithSize slightly underestimating the correct height - why?
I had the same Problem. I found the following in the Documentation:
To correctly draw and size multi-line text, pass
NSStringDrawingUsesLineFragmentOrigin in the options parameter.This method returns fractional sizes (in the size component of the
returned CGRect); to use a returned size to size views, you must raise
its value to the nearest higher integer using the ceil function.
So this solved it for me:
CGRect rect = [myLabel.text boundingRectWithSize:CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: myLabel.font}
context:nil];
rect.size.width = ceil(rect.size.width);
rect.size.height = ceil(rect.size.height);
Update (Swift 5.1)
An alternative Swift way to do this would be:
let size = myLabel.text!.size(
withAttributes: [.font: myLabel.font!]
)
let rect = CGSize(
width: ceil(size.width),
height: ceil(size.height)
)
See this answer for an Objective-C example.
How to get height for NSAttributedString at a fixed width
The answer is to use
- (void)drawWithRect:(NSRect)rect options:(NSStringDrawingOptions)options
but the rect
you pass in should have 0.0 in the dimension you want to be unlimited (which, er, makes perfect sense). Example here.
Related Topics
Swift3 Different Font in The All of The UIview with Localization Each
How to Pass Data Backwards to a View Controller After Passing Forward
Swift-Animate Cashapelayer Stroke Color
How to Remove The Fading Animation on .Ondelete Swiftui
Access Environment Variable Inside Global Function - Swiftui + Coredata
Cannot Increment Beyond Endindex
Why Extensions Cannot Add Stored Properties
Functional Programming Way of Doing Array Conversion
How to Determine Whether a Double Is an Integer
Comparing Time Without Date Swift3
Heightanchor.Constraint Not Change Height of View
iOS 10. Coredata Insert New Object Sig Abrt
Nsdocumentcontroller.Opendocument Not Allowing Selection of Custom File Type
Swift, Detect Ibeacons on The Background and Send Notifications When in Range
Swift: Change Speed of a Moveto Skaction
Generic Return Type Based on Class
How to Use Protocols for Stucts to Emulate Classes Inheritance