模态表中的 UITextView 不起作用

Posted

技术标签:

【中文标题】模态表中的 UITextView 不起作用【英文标题】:UITextView in a modal sheet is not working 【发布时间】:2019-09-14 14:22:00 【问题描述】:

为了使基于 UI 的 NSAttributedString 属性(在托管对象中)的编辑成为可能,使用 UITextView 代替 SwiftUI TextField 视图。文本视图位于由工作表函数呈现的模式视图中。

.sheet(isPresented: $presentSheet)  ...

(为了说明和重现,下面的代码是这个场景的简化版本)

模态视图用于编辑通过 ForEach 构造显示在列表中的选定模型项。选定的模型项作为 @Observable 对象传递给模态视图。

选择项目“A”时,模态视图和 UITextView 正确显示此模型项目。如果选择一个新项目“B”,模态视图会正确显示这个“B”项目。但如果现在正在编辑“B”,则更改将影响“A”对象。

这种行为的原因可能是 UIViewRepresentable 视图(代表 UITextView)只初始化了一次。从这里开始,这似乎是由 SwiftUI 中显示工作表(模态)视图的方式引起的(状态变量仅在工作表第一次出现时初始化,而不是第二次出现)。

我可以通过将所选项目作为@Binding 而不是@Observable 对象传递来解决此故障,尽管我不相信这是处理这种情况的正确方法,特别是因为一切正常,如果使用 SwiftUI TextField 代替 UITextView(在简化的情况下)。

值得一提,我似乎已经弄清楚 UITextView 的情况出了什么问题 - 不用说这解决了问题。

在下面列出的代码(重现问题)中,协调器的 init 函数有一个分配,它用父级初始化协调器。由于这是值而不是引用分配,并且由于 Coordinator 仅初始化一次,因此编辑 UITextView 可能会访问错误的父级。

再次,我不确定我的问题解决方案是否正确,因为使用 SwiftUI TextField 时一切正常。因此,我希望看到一些 cmets 解决这个问题。

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】:

一些更改将解决它:

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
    

【讨论】:

非常好的答案。它现在可以工作了,无需使用绑定在视图层次结构中向下传递模型对象。

以上是关于模态表中的 UITextView 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

UIAlertview 中的 UITextView 在 iOS 4.x 中不起作用

Angular UI 模态中的嵌入不起作用

UITextView setContentSize 不起作用?

ios 8 UITextView UIDataDetectorTypeLink 不起作用

UITextView sizeToFit 不起作用

UITextView contentInset 在 iOS 7 上的 UITextView 中不起作用?