Last active
May 12, 2025 23:02
-
-
Save niw/6f44f539709fc8a03aa86d09503e7efe to your computer and use it in GitHub Desktop.
Sample code to implement a vertically gorwing NSTextView in SwiftUI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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