问题
I'm looking to create an editable multi-line text box in Swift UI for macOS. I'd like to create a syntax highlighting text editor, so it'd be multi-line and change styles throughout the lines. Is this possible with the framework in its current state? I can find barely any documentation about it online.
回答1:
it can be useful, this is my first solution to get an NSTextView with SwiftUI:
import SwiftUI
import os
let uiLog = OSLog(subsystem: "com.visual-science.CryptiK", category: "UI")
class EditorCoordinator : NSObject, NSTextViewDelegate {
let textView: NSTextView;
let scrollView : NSScrollView
let text : Binding<NSAttributedString>
init(binding: Binding<NSAttributedString>) {
text = binding
textView = NSTextView(frame: .zero)
textView.autoresizingMask = [.height, .width]
textView.textStorage?.setAttributedString(text.wrappedValue)
textView.textColor = NSColor.textColor
scrollView = NSScrollView(frame: .zero)
scrollView.hasVerticalScroller = true
scrollView.autohidesScrollers = false
scrollView.autoresizingMask = [.height, .width]
scrollView.documentView = textView
super.init()
textView.delegate = self
}
func textDidChange(_ notification: Notification) {
switch notification.name {
case NSText.didChangeNotification :
text.wrappedValue = (notification.object as? NSTextView)?.textStorage ?? NSAttributedString(string: "")
default:
os_log(.error, log: uiLog, "Coordinator received unwanted notification")
}
}
}
struct DataTextEditorView: View, NSViewRepresentable {
typealias Coordinator = EditorCoordinator
typealias NSViewType = NSScrollView
let text : Binding<NSAttributedString>
func makeNSView(context: NSViewRepresentableContext<DataTextEditorView>) -> DataTextEditorView.NSViewType {
os_log(.info, log: uiLog, "%@", context.coordinator.scrollView)
return context.coordinator.scrollView
}
func updateNSView(_ nsView: NSScrollView, context: NSViewRepresentableContext<DataTextEditorView>) {
os_log(.debug, log: uiLog, "%@", context.coordinator.self)
os_log(.debug, log: uiLog, "%@", text.wrappedValue)
}
func makeCoordinator() -> EditorCoordinator {
os_log(.info, log: uiLog, "makeCoordinator")
let coordinator = EditorCoordinator(binding: text)
return coordinator
}
}
If like me, you just need to edit some text without attributes, you can replace NSAttributedString with just String and adapt the code for this simpler case.
回答2:
You can have a multi-line TextField
in SwiftUI (you just need to call .lineLimit(N)
on it to become multi-line capable), but text with multiple separate styles isn't currently supported. A TextField
just has a single font & style.
You can roll it yourself, though: create an NSViewRepresentable
implementation that vends an NSTextView
and bind it to an NSMutableAttributedText
property. You'll need to handle all the text view model synchronization and bindings updates yourself, but it is certainly do-able.
来源:https://stackoverflow.com/questions/58251487/multiline-editable-text-field-in-swiftui