Using Swift, I want to get the boundingRect of a glyph, in draw#rect in a UILabel.
The UILabel already has a size (say 300x300 in the example) and qualities such as the text being centered.
class RNDLabel: UILabel {
override func draw(_ rect: CGRect) {
let manager = NSLayoutManager()
let store = NSTextStorage(attributedString: NSAttributedString(
string: text!,
attributes: [NSAttributedString.Key.font: font]))
store.addLayoutManager(manager)
let textContainer = NSTextContainer(size: rect.size)
// note, intrinsicContentSize is identical there, no difference
manager.addTextContainer(textContainer)
let glyphRange = manager.glyphRange(
forCharacterRange: NSRange(location: 0, length: 1),
actualCharacterRange: nil)
let glyphRect = manager.boundingRect(
forGlyphRange: glyphRange, in: textContainer)
print("glyphRect \(glyphRect)")
...context?.addRect(glyphRect), context?.drawPath(using: .stroke)
super.draw(rect)
}
The green square is not correct - it should be more like these red squares!
There seems to be a number of problems:
surely the layoutManager I make, should get the qualities of the UILabel, eg "centered text"? (I believe you can't actually directly access the layoutManager of a UILabel, though?)
should we be using something like CTLineGetOffsetForStringIndex? Is that even possible in draw#rect
notice as well as not having the correct offset, the green box seems the wrong height anyway. (It looks more like a plain old intrinsicContentSize rather than a glyph bounding box.)
How to?
For the record, my overall aim is to move the glyph around, based on the actual glyph box (which of course is different for "y", "X", etc). But in general there are many useful reasons to know the box of a glyph.
It turns out the answer to this question seems to be:
In particular RobN. has pointed out that an investigation showed that in UILabel, _drawTextInRect:baselineCalculationOnly does the work and that is a big pile of ad hoc code.
A summary of the situation would seem to be that UILabel simply predates NSLayoutManager / Core Text and (as yet) just plain does not use those modern systems.
Only those modern systems give you this ...
... sort of access to glyph-by-glyph shapes.