在 SwiftUI 和 macOS 11 中获取多行 + 可滚动 TextView 中子字符串的 X/Y 位置

Get X/Y position of substring in multi-line + scrollable TextView in SwiftUI and macOS 11

计划

我已经使用以下实现在我的 Swift-app (macOS 11) 中实现了 TextView,这通过将 TextView 放入 ScrollViewer 使其可滚动:

https://gist.github.com/unnamedd/6e8c3fbc806b8deb60fa65d6b9affab0

现在,我正在尝试在文本的一侧显示注释,最终看起来应该是这样的:

我计划通过

实现这一目标
  1. 将自定义 AttributedString-key 设置为 TextView 的 NSAttributedString
  2. 在左侧添加第二个 ScrollView,其中包含注释,并同步两个 ScrollView 的滚动位置(即,左边一个和 TextView 中的那个。)
  3. 使用相关子字符串和place/draw annotation/connecting行计算每个注释的Y位置

问题

我尝试使用 textView.firstRect 函数(我在所有其他旧的 SO 问题中找到)来评估子字符串的 Y 位置,但是, 它似乎 return 正确的值,除非使用了 TextView 第一行中子字符串的位置。

    class TextViewExtended: NSTextView {    

func getAllRectangles() {
    for CurRange in self.selectedRanges {
        self.layoutManager!.ensureLayout(for: self.textContainer!) // S. 
        let CurRangeAsNSRange:NSRange = CurRange as! NSRange
        var actualRange = NSRange(location: 0, length: self.attributedString().length)
        let rect = self.firstRect(forCharacterRange: CurRangeAsNSRange, actualRange: &actualRange)
    }}}

问题

在 SwiftUI 和 macOS 11 中确定 TextView 子字符串坐标的正确方法是什么?或者有没有人有更简单的想法,我可以如何实现这一目标?

非常感谢您的建议!

Ps。我省略了 TextView 实现的完整代码,因为它紧跟上面的教程;如果我应该添加其他代码,请告诉我。

尝试使用 actualRange 更新矩形。像这样的事情:

rect = textView.firstRect(forCharacterRange: range, actualRange: &actualRange)
while actualRange.upperBound < rangeToCheck.upperBound {
    rangeToCheck.length = (rangeToCheck.upperBound - actualRange.upperBound)
    rangeToCheck.location = actualRange.upperBound
    rect = textView.firstRect(forCharacterRange: rangeToCheck, actualRange: &actualRange)
}