模态表中的UITextView无法正常工作

时间:2019-09-14 14:22:00

标签: swiftui

要使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
    }
}

1 个答案:

答案 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
    }
}