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