I'm trying to retrieve a glyph range for the given bounds in NSLayoutManager
. The built-in methods return the range for glyphs that are wholly or partially lying inside the bounds, and I need to find out which actually fit it.
For example:
let glyphRange = textView.layoutManager!.glyphRange(forBoundingRect: scrollView.contentView.bounds, in: textView.textContainer!)
let charRange = textView.layoutManager!.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil)
let range = Range(charRange, in: string)
string[range]
now produces a substring up to "not listening to explanations useless".
I've tried creating a substring and removing stuff word by word, until the height of the string fits my needs, but that becomes very slow. I'm writing a method (for both macOS and iOS) which has to take care of hundreds of such calculations in a very short time.
How could I return the range for glyphs wholly inside the bounds?
This can be achieved by enumerating line fragments. They are already laid out, so it comes with not much extra cost.
let desiredHeight = 300
var height = 0.0
textView.layoutManager!.enumerateLineFragments(forGlyphRange: glyphRange) { rect, usedRect, container, range, stop in
if usedRect.height + usedRect.origin.y <= desiredHeight {
height += usedRect.height
}
}
let newBounds = NSRect(x: 0, y:0, width: width, height: height)
let newGlyphRange = textView.layoutManager!.glyphRange(forBoundingRect: scrollView.contentView.bounds, in: textView.textContainer!)
let newCharRange = textView.layoutManager!.characterRange(forGlyphRange: newGlyphRange, actualGlyphRange: nil)
let newRange = Range(newCharRange, in: string)