NSLayoutManager boundingRectForGlyphRange is turned off by some points

I want to “highlight” certain words in a UITextView, not a solid color (which would be possible through NSAttributedString), but rather with a gradient and, possibly, with some other effects.

Therefore, I decided that it was necessary to manually create the view and overlay (or enclose) it using the bounding rectangles of this text.

To my surprise, this turned out to be quite simple. An example is inside a UIViewController, txtViewis UITextViewconnected as IBOutlet:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Converting to NSString as I need a NSRange for glphyRangeForCharacterRange
    // (a normal String in Swift returns a Range)
    let charRange = (txtView.text as NSString).rangeOfString("dolor sit er elit")
    assert(charRange.location != NSNotFound, "Character Range could not be found.")

    let glyphRange = txtView.layoutManager.glyphRangeForCharacterRange(charRange,
        actualCharacterRange: nil)
    let glyphContainer = txtView.layoutManager.textContainerForGlyphAtIndex(glyphRange.location, effectiveRange: nil)
    let glyphRect = txtView.layoutManager.boundingRectForGlyphRange(glyphRange,
        inTextContainer: glyphContainer!)

    let highlightView = UIView(frame: glyphRect)
    highlightView.alpha = 0.3
    highlightView.backgroundColor = UIColor.redColor()
    txtView.addSubview(highlightView)
}

Unfortunately, this leads to an overlay view (in red in the screenshot below), disconnecting from several points.

Simulator Screenshot showing the red rectangle being off by a few points

, . , , . Simulator iPhone 6 iOS 8.1.3.

( NSTextContainer ..), , CGRect "boundingRectForGlyphRange " ​​

( CoreText)?

+4
1

- textview textContainerInset:

var glyphRect = txtView.layoutManager.boundingRectForGlyphRange(glyphRange,
        inTextContainer: glyphContainer!)

glyphRect.origin.y += txtView.textContainerInset.top

!

+4

All Articles