使用 NSTextView/UITextView 排除 rects 不正确移动文本

Exclusion rects not shifting text properly with NSTextView/UITextView

我有一个带有一些排除项的 NSTextView,这样我就可以垂直移动文本,而不必向字符串添加换行符。但是,我注意到排除矩形相当有限,甚至可能有错误,因为我不能将文本垂直移动超过 textview 高度的 ~45%。我找到了一个解决方法,我将 textview 的高度增加了 2 倍,但这感觉很恶心,我宁愿这样做 "properly"

在上图中,我有三个文本视图(从左到右)

  1. 以编程方式将其封装在 NSScrollView、2x 高度
  2. 以编程方式使用 NSScrollView 封装。 2x 高度
  3. 使用界面生成器,常规高度。

排除矩形是用 CAShapeLayer 绘制的,您可以看到 "hello world new world" 没有正确定位在排除矩形之外。

我尝试了所有三个示例,以确保在封装在 NSScrollView 中时我没有遗漏有关 IB 默认设置或文本视图动态的内容(我是 AppKit 和 TextKit 的新手),然而,所有 3 个示例都出现了相同的错误。

更新文本排除矩形的代码

(每次滑块在右下角移动时,都会更新其文本矩形)

label.stringValue = "excl: \(sender.integerValue): height: \(view.frame.height)"
print(sender.integerValue)

let exclHeight: CGFloat = CGFloat(slider.integerValue)


[aTextView, bTextView, cTextView]
  .compactMap { [=11=] }
  .forEach {
    let rect = CGRect(
      x: 5,
      y: 5,
      width: aTextView.frame.width - 10,
      height: exclHeight)
    [=11=].wantsLayer = true
    [=11=].textContainer?.exclusionPaths.removeAll()
    [=11=].textContainer?.exclusionPaths.append(.init(rect: rect))
    [=11=].layer?.sublayers?.forEach {
      [=11=].removeFromSuperlayer()
    }

    let layer = CAShapeLayer()
    layer.frame = rect
    layer.backgroundColor = NSColor.blue.withAlphaComponent(0.2).cgColor
    layer.borderWidth = 1
    layer.borderColor = NSColor.white.cgColor
    [=11=].layer?.addSublayer(layer)
  }
}

问题似乎是 exclusionPath 在第一行之前。

只是玩弄参数,一个两行示例文本,其中 rect y 位于第一行之后,没有任何问题。

所以看起来问题是在 -[NSLayoutManager usedRectForTextContainer:]

中以 exclusionPaths 开头时计算容器高度
@interface LOLayoutManager : NSLayoutManager
@end

@implementation LOLayoutManager

- (NSRect)usedRectForTextContainer:(NSTextContainer *)container
{
    NSRect rect = [super usedRectForTextContainer:container];
    NSRect newRect = NSMakeRect(0, 0, NSMaxX(rect), NSMaxY(rect));
    return newRect;
}

@end

不是从 exclusionPaths 和行片段高度返回 y 位置,而是这个 returns 从 0, 0 开始的大矩形。只要 NSTextView 只包含一个文本容器,这就应该有效。