关于NSAttributedString绘图方法及NSStringDrawingOptions选项的技术咨询
Hey there! Let's tackle your questions about iOS text rendering and calculation step by step:
NSAttributedString.draw(with:options:context:) This instance method is your go-to tool for rendering rich text (strings with styling like custom fonts, colors, line spacing, or even attachments) directly into a specified rectangular area. Unlike basic NSString drawing methods, it respects all attributes attached to your string, so you can draw styled text exactly how you want it.
You’ll most commonly use this in the draw(_:) method of a custom UIView when you need custom text layouts that UILabel or UITextView can’t handle easily. For example, if you want to draw a multi-line string with different colors for different segments, or add custom line spacing, this method lets you render it precisely within the bounds you define.
The parameters give you fine-grained control:
- The
withparameter sets the target rectangle for drawing. optionsadjust how the text is laid out (we’ll dive deeper into these in the next question).contextcan track extra drawing details, like the actual range of text that was rendered, if you need that info later.
NSStringDrawingOptions.usesLineFragmentOrigin and option combinations Let’s break this into two clear parts:
What does usesLineFragmentOrigin do?
When calculating a text’s bounding rectangle (like in your code snippet), this option changes how the system interprets the rectangle you pass in:
- Without this option, the system treats the rectangle’s width as a maximum single-line width—it won’t wrap text, even if it’s longer than the width. The resulting height will only be that of a single line, no matter how much text you have.
- With
usesLineFragmentOrigin, the system uses the rectangle’s width as the maximum line width for wrapping. It breaks the text into lines that fit within that width, then calculates the total height needed to fit all those lines. That’s exactly why it’s in your code: you want to know how tall the text will be when wrapped toframe.width, so you can check if it stays within the 40-point height limit.
Why combine options like usesFontLeading.union(...)?
Each NSStringDrawingOptions flag adds a specific behavior to the calculation or drawing:
usesFontLeading: This makes the system include the font’s leading (extra space above and below the font’s baseline that’s part of the font’s design) when calculating line height. Without this, the calculation might only use the font’s ascender/descender height, leading to text being cut off or having incorrect spacing compared to how it actually renders.usesDeviceMetrics: This forces the calculation to use the actual device’s font rendering metrics instead of theoretical font data, making the result match exactly what you see on screen (great for avoiding layout discrepancies).
Developers combine these options using union() because they want multiple behaviors at once. For example, usesLineFragmentOrigin.union(.usesFontLeading) tells the system: "Wrap the text to this width, and make sure the line height calculation includes the font’s leading so it matches how the text will actually draw."
As a quick example: if you have a font with a leading value of 2 points, using usesFontLeading will add that extra space between lines, so the calculated height will be taller (and more accurate) than if you didn’t use it.
内容的提问来源于stack exchange,提问作者Ninja

