Skip to content

Instantly share code, notes, and snippets.

@niw
Last active May 12, 2025 23:02
Show Gist options
  • Save niw/6f44f539709fc8a03aa86d09503e7efe to your computer and use it in GitHub Desktop.
Save niw/6f44f539709fc8a03aa86d09503e7efe to your computer and use it in GitHub Desktop.
Sample code to implement a vertically gorwing NSTextView in SwiftUI
import AppKit
import SwiftUI
public struct TextView: NSViewRepresentable {
@Binding
var text: String
var font: NSFont?
public init(
text: Binding<String>
) {
self._text = text
}
public class Coordinator: NSObject, NSTextViewDelegate {
var parent: TextView
init(_ parent: TextView) {
self.parent = parent
}
public func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else {
return
}
parent.text = textView.string
}
}
public func makeCoordinator() -> Coordinator {
Coordinator(self)
}
public func makeNSView(context: Context) -> NSScrollView {
let nsView = NSTextView.scrollableTextView()
let textView = nsView.documentView as! NSTextView
textView.delegate = context.coordinator
textView.textContainerInset = .init(width: 10.0, height: 10.0)
nsView.documentView = textView
return nsView
}
public func updateNSView(_ nsView: NSScrollView, context: Context) {
(nsView.documentView as! NSTextView).string = text
}
public func sizeThatFits(_ proposal: ProposedViewSize, nsView: NSScrollView, context: Context) -> CGSize? {
let textView = nsView.documentView as! NSTextView
guard let textLayoutManager = textView.textLayoutManager else {
return nil
}
let rect = textLayoutManager.usageBoundsForTextContainer
print(rect)
let width = proposal.width ?? 0.0
let height = rect.height + textView.textContainerInset.height * 2
return CGSize(width: width, height: height)
}
}
struct MainView: View {
@State
private var text: String = "This is sample text.\nHello, World!"
var body: some View {
VStack {
ScrollView {
LazyVStack {
ForEach(Array(0..<100), id: \.self) { id in
Text("\(id)")
}
}
}
.border(.blue)
TextView(text: $text)
.border(.red)
.fixedSize(horizontal: false, vertical: true)
}
.scenePadding()
}
}
#Preview {
MainView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment