25

我的应用程序由一个NSScrollView其文档视图组成,其中包含许多垂直堆叠的NSTextViews- 每个都在添加文本时在垂直方向上调整大小。

目前,这一切都在代码中进行管理。NSTextViews自动调整大小,但我用 观察它们的大小,重新计算它们的NSViewFrameDidChangeNotification所有原点以使它们不重叠,并调整它们的超级视图(滚动视图的文档视图)的大小,以便它们都适合并且可以滚动到。

这似乎是自动布局的完美候选者!我NSLayoutConstraints在第一个文本视图及其容器、最后一个文本视图及其容器以及每个文本视图之间进行设置。然后,如果任何文本视图增长,它会自动“下推”它下面的文本视图的起源以满足约束,最终增加文档视图的大小,每个人都很高兴!

除了,似乎没有办法NSTextView在基于约束的布局中添加文本时自动增长?使用与之前输入的文本自动扩展的完全相同NSTextView的内容,如果我没有为其高度指定约束,它默认为 0 并且不显示。如果我确实指定了一个约束,即使是 >=20 之类的不等式,它也会停留在该大小上,并且不会随着添加文本而增长。

我怀疑这与 NSTextView 的实现有关-intrinsicContentSize,默认情况下返回(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric).

所以我的问题是:如果我根据文本的布局进行子类化NSTextView以返回更有意义intrinsicContentSize的内容,那么我的自动布局会按预期工作吗?

intrinsicContentSize关于实现垂直调整大小的 NSTextView 的任何指针?

4

4 回答 4

31

我正在做一个非常相似的设置——一个包含文本视图的垂直堆栈视图,这些视图可以扩展以适应其文本内容并使用自动布局。

到目前为止,我不得不子类化NSTextView,这感觉不干净,但在实践中效果很好:

- (NSSize) intrinsicContentSize {
    NSTextContainer* textContainer = [self textContainer];
    NSLayoutManager* layoutManager = [self layoutManager];
    [layoutManager ensureLayoutForTextContainer: textContainer];
    return [layoutManager usedRectForTextContainer: textContainer].size;
}

- (void) didChangeText {
    [super didChangeText];
    [self invalidateIntrinsicContentSize];
}

奇怪的是,添加时文本视图的初始大小addSubview不是固有大小;我还没有弄清楚如何发出第一个失效(挂钩viewDidMoveToSuperview没有帮助),但我相信我最终会弄明白的。

于 2013-01-22T23:15:33.347 回答
12

我在使用 NSTextField 时遇到了类似的问题,结果证明这是由于视图想要沿垂直方向紧紧地拥抱其文本内容。因此,如果您将内容拥抱优先级设置为低于其他约束的优先级,它可能会起作用。例如:

[textView setContentHuggingPriority:NSLayoutPriorityFittingSizeCompression-1.0 forOrientation:NSLayoutConstraintOrientationVertical];

在 Swift 中,这将是:

setContentHuggingPriority(NSLayoutConstraint.Priority.fittingSizeCompression, for:NSLayoutConstraint.Orientation.vertical)
于 2012-07-10T16:56:20.430 回答
6

以下是如何在 Swift 3 中使用 Auto Layout 制作扩展的 NSTextView在此处输入图像描述

  • 我使用Anchors进行自动布局
  • 使用textDidChangeNSTextDelegate. NSTextViewDelegate符合NSTextDelegate
  • 这个想法是textViewedges约束的,这意味着每当它intrinsicContentSize发生变化时,它将扩展其父级,即scrollView

    import Cocoa
    import Anchors
    
    class TextView: NSTextView {
      override var intrinsicContentSize: NSSize {
        guard let manager = textContainer?.layoutManager else {
          return .zero
        }
    
        manager.ensureLayout(for: textContainer!)
    
        return manager.usedRect(for: textContainer!).size
      }
    }
    
    class ViewController: NSViewController, NSTextViewDelegate {
    
      @IBOutlet var textView: NSTextView!
      @IBOutlet weak var scrollView: NSScrollView!
      override func viewDidLoad() {
        super.viewDidLoad()
    
        textView.delegate = self
    
        activate(
          scrollView.anchor.top.constant(100),
          scrollView.anchor.paddingHorizontally(30)
        )
    
        activate(
          textView.anchor.edges
        )
      }
    
      // MARK: - NSTextDelegate
      func textDidChange(_ notification: Notification) {
        guard let textView = notification.object as? NSTextView else { return }
    
        print(textView.intrinsicContentSize)
        textView.invalidateIntrinsicContentSize()
      }
    }
    
于 2017-05-19T06:31:18.970 回答
3

类准备复制和粘贴。斯威夫特 4.2,macOS 10.14

class HuggingTextView: NSTextView, NSTextViewDelegate {

    //MARK: - Initialization

    override init(frame: NSRect) {
        super.init(frame: frame)
        delegate = self
    }

    override init(frame frameRect: NSRect, textContainer container: NSTextContainer?) {
        super.init(frame: frameRect, textContainer: container)
        delegate = self
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        delegate = self
   }

    //MARK: - Overriden

    override var intrinsicContentSize: NSSize {
        guard let container = textContainer, let manager = container.layoutManager else {
            return super.intrinsicContentSize
        }
        manager.ensureLayout(for: container)
        return manager.usedRect(for: container).size
    }

    //MARK: - NSTextViewDelegate

    func textDidChange(_ notification: Notification) {
        invalidateIntrinsicContentSize()
    }

}
于 2018-11-12T13:36:47.467 回答