1

I'm using NSTextView as a text editor, and I want to make it about 20 PX taller than the recalculation after the user enters the text.

That is, when NSTextView rolls in the end of the NSScrollView, there is a blank area that makes the user do not have to enter a return to make a blank line. In this way, the text of the tail will always be on the upper side to facilitate the user's visual experience.

How do you do this?

How to resize NSTextView according to its content?

I found some hints in this question, but the connection was invalid after too long.

Simon
  • 438
  • 4
  • 14
  • Possible duplicate of [How to resize NSTextView according to its content?](https://stackoverflow.com/questions/2654580/how-to-resize-nstextview-according-to-its-content) – Willeke Aug 05 '18 at 14:50

1 Answers1

0

Since your NSTextView is nested inside an NSScrolView most of the times, you can play with the scroll view's margins.

The solution below is for storyboard-based app, which has a minium requirement of OS X 10.10 (Yosemite):

class ViewController: NSViewController {
    @IBOutlet weak var scrollView: NSScrollView!
    @IBOutlet weak var textView: NSTextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.layoutManager?.delegate = self
        scrollView.automaticallyAdjustsContentInsets = false
    }
}

extension ViewController: NSLayoutManagerDelegate {
    func layoutManager(_ layoutManager: NSLayoutManager, didCompleteLayoutFor textContainer: NSTextContainer?, atEnd layoutFinishedFlag: Bool) {
        guard let textContainer = textContainer else { return }

        let textRect = layoutManager.usedRect(for: textContainer)
        let bottomSpace: CGFloat = 20.0
        let bottomInset: CGFloat = (textRect.height + bottomSpace) > scrollView.bounds.height ? bottomSpace : 0

        scrollView.contentInsets.bottom = bottomInset
        scrollView.scrollerInsets.bottom = -bottomInset
    }
}

Edit: how do I scroll the text view if I click on the bottom space?

You can play around with NSParagraphStyle to add some after the last paragraph. Or you can use the Responder Chain and make view controller change the cursor position to the end of the text view:

class ViewController: NSViewController {
    // ...

    override func mouseUp(with event: NSEvent) {
        let bottomSpace = scrollView.contentInsets.bottom
        let clickLocation = self.view.convert(event.locationInWindow, to: textView)
        let bottomRect = CGRect(x: 0, y: textView.bounds.height, width: textView.bounds.width, height: bottomSpace)

        if bottomRect.contains(clickLocation) {
            textView.moveToEndOfDocument(self)
        }
    }
}

If you want multiple text views with the same behaviour, time to design your own class.

Code Different
  • 90,614
  • 16
  • 144
  • 163
  • Thank you for the answer. This effectively creates a blank area, but when I click on the blank area, the focus of the TextView will not be at the end, which is different from the original performance. Is there any possibility of improvement? – Simon Aug 06 '18 at 01:19