与 "RichTextField" 绑定(即 NSViewRepresentable 中的 NSTextView)- 值在重绘、LostFocus 等后重置
Binding with "RichTextField" (i.e. NSTextView in NSViewRepresentable) - Value resets after redraw, LostFocus, etc
我正在努力使用定制的 RichTextField,即 NSViewRepresentable 中的 NSTextView,它具有以下代码(在 的帮助下编程):
在代码中设置 attributedString 有效,我可以更改格式,但是一旦应用程序失去焦点,RichTextField 就会重置为以编程方式设置的最后一个值:
此外,在列表中使用 RichTextField 时,应用程序会进入循环。
RichTextField
import Foundation
import SwiftUI
struct RichTextField: NSViewRepresentable {
typealias NSViewType = NSTextView
@Binding var attributedString: NSMutableAttributedString
var isEditable: Bool
func makeNSView(context: Context) -> NSTextView {
let textView = NSTextView(frame: .zero)
textView.textStorage?.setAttributedString(self.attributedString)
textView.isEditable = isEditable
textView.translatesAutoresizingMaskIntoConstraints = false
textView.autoresizingMask = [.width, .height]
return textView
}
func updateNSView(_ nsView: NSTextView, context: Context) {
nsView.textStorage?.setAttributedString(self.attributedString)
}
}
查看
import SwiftUI
struct EditWindow: View {
@ObservedObject var model: EditEntryViewModel
var body: some View {
VStack (alignment: .leading, spacing: 20) {
RichTextField(attributedString: self.$model.answer1, isEditable: true)
.frame(maxWidth: .infinity, maxHeight: .infinity)
Spacer()
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
ViewModel
import Foundation
import SwiftUI
class EditEntryViewModel: ObservableObject {
init(entryID: Int32) {
let entryToUse = db.getEntry(id: entryID)
id = entryToUse!.id
answer1 = entryToUse!.answer1.getNSMutableAttributedStringFromHTML() // Converts HTML from the DB to a NSMutableAttributedString
}
@Published var id: Int32
@Published var answer1: NSMutableAttributedString = NSMutableAttributedString() {
didSet {
print("NEW answer1: " + answer1.string)
}
}
}
不知道有没有办法将attributedString绑定到ViewModel?
非常感谢您的帮助。
不确定这是否是正确的方法,但我得到了使用以下代码的绑定:
import Foundation
import SwiftUI
struct RichTextField: NSViewRepresentable {
typealias NSViewType = NSTextView
@Binding var attributedString: NSAttributedString
var isEditable: Bool
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView(context: Context) -> NSTextView {
let textView = NSTextView(frame: .zero)
textView.textStorage?.setAttributedString(self.attributedString)
textView.isEditable = isEditable
textView.delegate = context.coordinator
textView.translatesAutoresizingMaskIntoConstraints = false
textView.autoresizingMask = [.width, .height]
return textView
}
func updateNSView(_ nsView: NSTextView, context: Context) {
nsView.textStorage!.setAttributedString(self.attributedString)
}
// Source: https://medium.com/fantageek/use-xib-de9d8a295757
class Coordinator: NSObject, NSTextViewDelegate {
let parent: RichTextField
init(_ RichTextField: RichTextField) {
self.parent = RichTextField
}
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else { return }
self.parent.attributedString = textView.attributedString()
}
}
}
(尽管在列表(不可编辑)中使用 RichTextField 时我仍然收到“检测到循环”错误。)
我正在努力使用定制的 RichTextField,即 NSViewRepresentable 中的 NSTextView,它具有以下代码(在
在代码中设置 attributedString 有效,我可以更改格式,但是一旦应用程序失去焦点,RichTextField 就会重置为以编程方式设置的最后一个值:
此外,在列表中使用 RichTextField 时,应用程序会进入循环。
RichTextField
import Foundation
import SwiftUI
struct RichTextField: NSViewRepresentable {
typealias NSViewType = NSTextView
@Binding var attributedString: NSMutableAttributedString
var isEditable: Bool
func makeNSView(context: Context) -> NSTextView {
let textView = NSTextView(frame: .zero)
textView.textStorage?.setAttributedString(self.attributedString)
textView.isEditable = isEditable
textView.translatesAutoresizingMaskIntoConstraints = false
textView.autoresizingMask = [.width, .height]
return textView
}
func updateNSView(_ nsView: NSTextView, context: Context) {
nsView.textStorage?.setAttributedString(self.attributedString)
}
}
查看
import SwiftUI
struct EditWindow: View {
@ObservedObject var model: EditEntryViewModel
var body: some View {
VStack (alignment: .leading, spacing: 20) {
RichTextField(attributedString: self.$model.answer1, isEditable: true)
.frame(maxWidth: .infinity, maxHeight: .infinity)
Spacer()
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
ViewModel
import Foundation
import SwiftUI
class EditEntryViewModel: ObservableObject {
init(entryID: Int32) {
let entryToUse = db.getEntry(id: entryID)
id = entryToUse!.id
answer1 = entryToUse!.answer1.getNSMutableAttributedStringFromHTML() // Converts HTML from the DB to a NSMutableAttributedString
}
@Published var id: Int32
@Published var answer1: NSMutableAttributedString = NSMutableAttributedString() {
didSet {
print("NEW answer1: " + answer1.string)
}
}
}
不知道有没有办法将attributedString绑定到ViewModel?
非常感谢您的帮助。
不确定这是否是正确的方法,但我得到了使用以下代码的绑定:
import Foundation
import SwiftUI
struct RichTextField: NSViewRepresentable {
typealias NSViewType = NSTextView
@Binding var attributedString: NSAttributedString
var isEditable: Bool
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView(context: Context) -> NSTextView {
let textView = NSTextView(frame: .zero)
textView.textStorage?.setAttributedString(self.attributedString)
textView.isEditable = isEditable
textView.delegate = context.coordinator
textView.translatesAutoresizingMaskIntoConstraints = false
textView.autoresizingMask = [.width, .height]
return textView
}
func updateNSView(_ nsView: NSTextView, context: Context) {
nsView.textStorage!.setAttributedString(self.attributedString)
}
// Source: https://medium.com/fantageek/use-xib-de9d8a295757
class Coordinator: NSObject, NSTextViewDelegate {
let parent: RichTextField
init(_ RichTextField: RichTextField) {
self.parent = RichTextField
}
func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else { return }
self.parent.attributedString = textView.attributedString()
}
}
}
(尽管在列表(不可编辑)中使用 RichTextField 时我仍然收到“检测到循环”错误。)