首页 > 解决方案 > 排除使用 NSTextView/UITextView 无法正确移动文本

问题描述

我有一个NSTextView带有一些排除的矩形,所以我可以垂直移动文本,而不必求助于在字符串中添加换行符。但是,我注意到排除 rect 相当有限,甚至可能有问题,因为我不能将文本垂直移动超过 textview 高度的约 45%。我找到了一种解决方法,我将 textview 的高度增加了 2 倍,但这感觉很恶心,我宁愿“正确”地做

在此处输入图像描述

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

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

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

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

更新文本排除矩形的代码

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

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

let exclHeight: CGFloat = CGFloat(slider.integerValue)


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

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

标签: cocoanstextviewtextkit

解决方案


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

只需使用参数,y在第一行之后放置矩形的两行示例文本就可以正常工作。

所以看起来问题是计算容器高度时,它以 excludePaths 开头-[NSLayoutManager usedRectForTextContainer:]

@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

y这不是从 excludePaths 和线段高度返回位置,而是返回一个从 开始的大矩形0, 0。只要 NSTextView 只包含一个文本容器,这应该可以工作。


推荐阅读