要使NSAttributedString属性(在托管对象中)的基于UI的编辑成为可能,请使用 UITextView 代替SwiftUI TextField View。文本视图位于由图纸功能呈现的模式视图中。
.sheet(isPresented: $presentSheet) { ...
(为说明和重现,下面的代码是此方案的简化版本)
模态视图用于编辑选定的模型项,该模型项通过 ForEach 构造显示在列表中。所选模型项将作为@Observable对象传递给模态视图。
选择项目“ A”时,模式视图和 UITextView 会正确显示此模型项目。如果选择一个新项目“ B”,模态视图将正确显示该“ B”项目。但是,如果现在正在编辑“ B”,则更改将影响“ A”对象。
此行为的原因可能是 UIViewRepresentable 视图(代表 UITextView )仅初始化了一次。在此之后,这似乎是由于SwiftUI中的工作表(模式)视图呈现方式(状态变量仅在工作表首次出现时才初始化,而在第二次出现时才初始化)。
我可以通过将选定的项目作为@Binding而不是@Observable对象传递来解决此故障,尽管我不认为这是处理这种情况的正确方法,尤其是因为如果使用SwiftUI TextField 代替 UITextView (在简化情况下)。
值得一提的是,我似乎已经弄清楚了 UITextView 情况出了什么问题-并不是说这可以解决问题。
在下面列出的代码中(此问题已得到解决),协调器的init函数具有一个赋值,该赋值用父级初始化协调器。由于这是值而不是参考分配,并且由于协调器仅初始化一次,所以对 UITextView 的编辑可能会访问错误的父级。
同样,我不确定该解决方案是否正确,因为使用SwiftUI TextField 时一切正常。因此,我希望看到有关此问题的一些评论。
struct ContentView: View {
var states = [StringState("A"), StringState("B"), StringState("C"), StringState("D"), StringState("E")]
@State var presentSheet = false
@State var state = StringState("A")
var body: some View {
VStack {
Text("state = \(state.s)")
ForEach(states) { s in
Button(action: {
self.state = s
self.presentSheet.toggle()
})
{
Text("\(s.s)")
}
}
}
.sheet(isPresented: $presentSheet) {
EditView(state: self.state, presentSheet: self.$presentSheet)
}
}
}
struct EditView: View
{
@ObservedObject var state: StringState
@Binding var presentSheet: Bool
var body: some View {
VStack {
Text("\(state.s)")
TextView(string: $state.s) // Edit Not OK
TextField("", text: $state.s ) // Edit OK
Button(action: {
self.presentSheet.toggle()
})
{ Text("Back") }
}
}
}
struct TextView: UIViewRepresentable
{
@Binding var string: String
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UITextView
{
let textview = UITextView(frame: CGRect.zero)
textview.delegate = context.coordinator
return textview
}
func updateUIView(_ uiView: UITextView, context: Context)
{
uiView.text = string
}
class Coordinator : NSObject, UITextViewDelegate
{
var parent: TextView
init(_ textView: TextView) {
self.parent = textView
}
func textViewDidChange(_ textView: UITextView)
{
self.parent.string = textView.text!
}
}
}
class StringState: Identifiable, ObservableObject
{
let ID = UUID()
var s: String
init(_ s : String) {
self.s = s
}
}
答案 0 :(得分:0)
一些更改将解决此问题:
func updateUIView(_ uiView: UITextView, context: Context)
{
uiView.text = string
context.coordinator.parent = self
}
还将@Published添加到您的ObservableObject:
class StringState: Identifiable, ObservableObject
{
let ID = UUID()
@Published var s: String
init(_ s : String) {
self.s = s
}
}