iosswiftdrawrectnslayoutmanager

Getting a glyph boundingRect in draw#rect in UILabel


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)
    }

enter image description here

The green square is not correct - it should be more like these red squares!

enter image description here

There seems to be a number of problems:

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.


Solution

  • It turns out the answer to this question seems to be:

    In fact, surprisingly or not, you basically have no access to glyph information in UILabel specifically.

    So realistically you can't get those glyph "actual shapes" in UILabel.

    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 ...

    enter image description here

    ... sort of access to glyph-by-glyph shapes.