Using Autolayout with expanding NSTextViews

烂漫一生 提交于 2019-11-29 20:38:09

I had a similar problem with an NSTextField, and it turned out that it was due to the view wanting to hug its text content tightly along the vertical orientation. So if you set the content hugging priority to something lower than the priorities of your other constraints, it may work. E.g.:

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

And in Swift, this would be:

setContentHuggingPriority(NSLayoutConstraint.Priority.fittingSizeCompression, for:NSLayoutConstraint.Orientation.vertical)

I am working on a very similar setup — a vertical stack of views containing text views that expand to fit their text contents and use autolayout.

So far I have had to subclass NSTextView, which is does not feel clean, but works superbly in practice:

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

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

The initial size of the text view when added with addSubview is, curiously, not the intrinsic size; I have not yet figured out how to issue the first invalidation (hooking viewDidMoveToSuperview does not help), but I'm sure I will figure it out eventually.

Here is how to make an expanding NSTextView using Auto Layout, in Swift 3

  • I used Anchors for Auto Layout
  • Use textDidChange from NSTextDelegate. NSTextViewDelegate conforms to NSTextDelegate
  • The idea is that textView has edges constraints, which means whenever its intrinsicContentSize changes, it will expand its parent, which is 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()
      }
    }
    

Class ready for copying and pasting. Swift 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()
    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!