我有一个NSTextVIew
,其中我仅显示标准字母中的等宽字符。因此,没有数字,特殊字符,表情符号等。每个字符都等于一个字形。在文本顶部,我需要绘制一些形状,并且我正在寻找一种从文本系统访问某些度量的方法:
请看图片以了解我的意思。
似乎没有可以直接使用的任何属性,或者至少我没有找到它们,所以现在我使用文本视图的layoutManager
获取这些值:
对于第一个,我通过layoutmanager的boundingRect(forGlyphRange glyphRange: NSRange, in container: NSTextContainer) -> NSRect
方法获得了两个相邻字符的包围式矩形,并减去了两个矩形的origin.x。
对于第二个字符,我可以使用相同的功能,但是随后我需要知道第二行中第一个字符的范围。或遍历所有字符,并且一旦包围的rect的origin.y改变,我在第二行上就有第一个字符,并且我可以计算两行之间的距离。
EDIT:这是使用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)
}
我也看过从defaultParagraphStyle
获取这些内容,但是如果我访问它,那就是nil
。
也许还有另一种更简单的方法来获取这些值?
[经过更多搜索和反复试验后,我发现distanceBetweenLines
可以从字体指标和lineHeightMultiple计算出来,这是NSParagraphStyle
的属性,但也可以在段落样式之外定义,即我做什么。
所以最后这有效:
let distanceBetweenLines = layoutManager.defaultLineHeight(for: myTextFont) * lineHeightMultiple
对于distanceBetweenCharacters
,我还没有找到其他解决方案。
编辑
基于下面评论中@Willeke的建议,我现在如下计算distanceBetweenCharacters
:
let distanceBetweenCharacters = myTextFont.advancement(forCGGlyph: layoutManager.cgGlyph(at: 0)).width + myKerning