I have an NSTextVIew
in which I am only showing mono-spaced characters from the standard alphabet. So no numbers, special characters, emojis, etc. Each character equals one glyph. On top of the text I need to draw some shapes, and I am looking for a way to access some metrics from the text system:
- the distance from one character to the next one
- the distance from one line to the next one
See the picture for what I mean.
There don't seem to be any properties that I can use directly, or at least I haven't found them, so I am now use the text view's layoutManager
to obtain these values:
For the first one I obtain the enclosing rects for two adjacent characters via the boundingRect(forGlyphRange glyphRange: NSRange, in container: NSTextContainer) -> NSRect
method of the layoutmanager, and subtract the origin.x for both rects.
For the second one, I could use the same function, but then I need to know the range for the first character on the second line. Or iterate over all the characters and once the origin.y of the enclosing rect changes, I have the first character on the second line and I can calculate the distance between two lines.
EDIT : here's possible code using the layoutManager:
typealias TextMetrics = (distanceBetweenCharacters: CGFloat, distanceBetweenLines: CGFloat)
var metrics: TextMetrics = self.textMetrics() // need to update when text changes
func textMetrics() -> TextMetrics {
guard let lm = self.layoutManager,
let tc = self.textContainer
else { return (0,0)
}
var distanceBetweenCharacters: CGFloat = 0.0
var distanceBetweenLines: CGFloat = 0.0
if string.count > 2 {
let firstRect = lm.boundingRect(forGlyphRange: NSRange(location: 0, length: 1), in: tc)
let secondRect = lm.boundingRect(forGlyphRange: NSRange(location: 1, length: 1), in: tc)
distanceBetweenCharacters = secondRect.maxX - firstRect.maxX
for (index, _) in string.enumerated() {
let rect = lm.boundingRect(forGlyphRange: NSRange(location: index, length: 1), in: tc)
if rect.maxY > firstRect.maxY { // reached next line
distanceBetweenLines = rect.maxY - firstRect.maxY
break
}
}
}
return (distanceBetweenCharacters, distanceBetweenLines)
}
I also looked at getting these from the defaultParagraphStyle
, but if I access that, it is nil
.
Is there maybe another, easier way to obtain these values?