Expand NSViewRepresentable (NSTextView) height based on window height

Viewed 312

I created an NSViewRepresentable structure that manages the state of an NSTextView. The view, by default, only has one line and I'd like to extend that to the edge of the window.

The view is defined as such:

struct Editor: View, NSViewRepresentable {

    @Binding var text: String

    func makeNSView(context: Context) -> NSTextView {
        let view = NSTextView()
        view.font = NSFont.monospacedSystemFont(ofSize: 12, weight: .regular)
        return view
    }

    func updateNSView(_ view: NSTextView, context: Context) {
        let attributedText = NSMutableAttributedString(string: text)
        view.textStorage?.setAttributedString(attributedText)
    }
}

Current view

It currently looks like this, it adds lines as you go. Is there a way for the darker text area to be expanded to the bottom of the window automatically?

1 Answers

You can use NSTextView.scrollableTextView() to do this:

struct ContentView : View {
    @State var text = ""
    var body: some View {
        VStack {
            Editor(text: $text)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

struct Editor: View, NSViewRepresentable {

    @Binding var text: String

    func makeNSView(context: Context) -> NSView {
        let scrollView = NSTextView.scrollableTextView()
        guard let textView = scrollView.documentView as? NSTextView else {
            return scrollView
        }
        textView.font = NSFont.monospacedSystemFont(ofSize: 12, weight: .regular)
        context.coordinator.textView = textView
        return scrollView
    }

    func updateNSView(_ view: NSView, context: Context) {
        let attributedText = NSMutableAttributedString(string: text)
        context.coordinator.textView?.textStorage?.setAttributedString(attributedText)
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    
    class Coordinator {
        var textView : NSTextView?
    }
}
Related