NSLayoutManager boundingRectForGlyphRange off by some Points

邮差的信 提交于 2019-12-01 16:34:06

问题


I want to "highlight" specific words in UITextView, not with a solid color (which would be possible via NSAttributedString), but rather with a gradient and maybe some other fancy effects.

Hence, I decided it would be necessary to manually create a view and overlay (or underlay) it using the bounding rectangles of the given text.

To my surprise this turned out to be pretty straightforward. Example is inside a UIViewController, txtView being a UITextView connected 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)
}

Sadly, this leads to the overlain view (in red in the below screenshot), being off by a few points.

It always seems to be off by the same amount. Which would mean I could probably hardcode, but that has never been a good idea. Tested this in Simulator with various devices and on an iPhone 6 with iOS 8.1.3.

I also tried other variations (by creating my own NSTextContainer etc.) as inspired by the question on how to get a CGRect for a substring and "boundingRectForGlyphRange does not always work for all strings"

Any ideas (besides resorting to CoreText)?


回答1:


Try adjusting the glyph rect by the textview's textContainerInset:

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

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

That should do the trick!



来源:https://stackoverflow.com/questions/28330772/nslayoutmanager-boundingrectforglyphrange-off-by-some-points

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!