访问 NSTextView 指标

Accessing NSTextView metrics

我有一个 NSTextVIew,其中我只显示标准字母表中的等宽字符。所以没有数字、特殊字符、表情符号等。每个字符等于一个字形。在文本之上我需要绘制一些形状,我正在寻找一种从文本系统访问一些指标的方法:

  1. 一个字符到下一个字符的距离
  2. 一行到下一行的距离

看图就是我的意思

好像没有我可以直接使用的属性,或者至少我还没有找到,所以我现在使用文本视图的layoutManager来获取这些值:

对于第一个,我通过布局管理器的 boundingRect(forGlyphRange glyphRange: NSRange, in container: NSTextContainer) -> NSRect 方法获得了两个相邻字符的封闭矩形,并减去两个矩形的 origin.x。

对于第二个,我可以使用相同的函数,但是我需要知道第二行第一个字符的范围。或者遍历所有字符,一旦封闭矩形的 origin.y 发生变化,我在第二行有第一个字符,我可以计算两行之间的距离。

EDIT :这是使用布局管理器的可能代码:

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