Доступ к метрикам NSTextView - PullRequest
       90

Доступ к метрикам NSTextView

0 голосов
/ 20 февраля 2020

У меня есть NSTextVIew, в котором я показываю только одинарные символы из стандартного алфавита. Так что никаких цифр, специальных символов, смайликов и т. Д. c. Каждый символ равен одному глифу. Поверх текста мне нужно нарисовать несколько фигур, и я ищу способ доступа к некоторым метрикам из текстовой системы:

  1. расстояние от одного символа до следующего
  2. расстояние от одной линии до следующей

См. Картинку, что я имею в виду.

enter image description here

Там у меня нет свойств, которые я могу использовать напрямую, или, по крайней мере, я их не нашел, поэтому теперь я использую текстовое представление layoutManager, чтобы получить эти значения:

Для первого Я получаю заключающие строки для двух смежных символов с помощью метода boundingRect(forGlyphRange glyphRange: NSRange, in container: NSTextContainer) -> NSRect компоновщика и вычитаю origin.x для обеих сторон.

Для второго я мог бы использовать ту же функцию, но затем я нужно знать диапазон для первого символа во второй строке. Или перебрать все символы, и как только 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.

Возможно, есть другой, более простой способ получить эти значения?

1 Ответ

0 голосов
/ 22 февраля 2020

После еще нескольких поисков, проб и ошибок я обнаружил, что distanceBetweenLines может быть вычислено из метрик шрифта и lineHeightMultiple, который является свойством NSParagraphStyle, но также может быть определен вне стиля абзаца, который это то, что я делаю.

В итоге это работает:

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

Для distanceBetweenCharacters я не нашел другого решения.

РЕДАКТИРОВАТЬ

Основываясь на предложении @Willeke в комментарии ниже, теперь я вычисляю distanceBetweenCharacters следующим образом:

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