【问题标题】:Accessing NSTextView metrics访问 NSTextView 指标
【发布时间】:2020-06-04 21:27:27
【问题描述】:

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

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

看图了解我的意思。

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

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

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

编辑:这是使用 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

是否有其他更简单的方法来获取这些值?

【问题讨论】:

    标签: swift macos nstextview nslayoutmanager


    【解决方案1】:

    经过一番搜索和反复试验,我发现distanceBetweenLines可以从字体度量和lineHeightMultiple计算出来,这是NSParagraphStyle的一个属性,但也可以在段落样式之外定义,即我就是这样做的。

    所以最后这行得通:

    let distanceBetweenLines = layoutManager.defaultLineHeight(for: myTextFont) * lineHeightMultiple
    

    对于distanceBetweenCharacters,我还没有找到其他解决方案。

    编辑

    根据下面评论中@Willeke 的建议,我现在计算distanceBetweenCharacters 如下:

    let distanceBetweenCharacters = myTextFont.advancement(forCGGlyph: layoutManager.cgGlyph(at: 0)).width + myKerning
    

    【讨论】:

    • NSFont.advancement(forCGGlyph:) 怎么样?
    • 不,这给出了不同的值。在这种情况下,15.8 使用我的计算,10.8 使用 NSFont.advancement(forCGGlyph:)
    • 哦,但是等等,差值是 5,这就是我用于字距调整的值...
    猜你喜欢
    • 1970-01-01
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    • 2023-02-10
    • 1970-01-01
    • 2017-10-23
    • 2019-09-21
    • 2020-06-25
    相关资源
    最近更新 更多