2

提供以下 UIViewRepresentable isEditing 和 onCommit 属性的最佳方法是什么?我希望它在 SwiftUI 中调用 TextFields 时具有相同的功能(您可以在其中添加代码以说明按下返回键 [onCommit] 或单击文本字段 [isEditing] 时的操作)

struct TextView: UIViewRepresentable {
@Binding var text: String

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}

func makeUIView(context: Context) -> UITextView {
    
    let myTextView = UITextView()
    myTextView.delegate = context.coordinator
    
    myTextView.font = UIFont(name: "HelveticaNeue", size: 16)
    myTextView.isScrollEnabled = true
    myTextView.isEditable = true
    myTextView.isUserInteractionEnabled = true
    myTextView.backgroundColor = UIColor(white: 0.0, alpha: 0.00)
    myTextView.textColor = UIColor.black
    
    return myTextView
}

func updateUIView(_ uiView: UITextView, context: Context) {
    uiView.text = text
}

class Coordinator : NSObject, UITextViewDelegate {
    
    var parent: TextView
    
    init(_ uiTextView: TextView) {
        self.parent = uiTextView
        
    }
    
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if (text == "\n") {
            textView.resignFirstResponder()
        }
        return true
    }
    
    func textViewDidChange(_ textView: UITextView) {
        print("text now: \(String(describing: textView.text!))")
        self.parent.text = textView.text
    }
    
    
    
    
}
}

旁注:我不知道为什么,但我传入的绑定变量并没有改变实际值。我知道是因为我使用 get/set 属性设置了一个自定义绑定,并且该集合没有打印该值。(这个值应该是传入textview的文本)

let binding = Binding<String>(get: {
        self.bindingVariableName
    }, set: {
        print("set the value")
        self.bindingVariableName = $0
    }
    )
4

1 回答 1

4

提交

您可以将函数作为变量传递,以使它们在正确的位置执行,例如:

struct TextView: UIViewRepresentable {
    @Binding var text: String

    var onCommit: ()->()
    ...
}

... {
        ...
        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            if (text == "\n") {
                textView.resignFirstResponder()
                parent.onCommit() // <- execute here
            }
            return true
        }
}

并像这样使用它:

TextView(text: $text, onCommit: {
    print("Committed")
})

可以应用类似的检测变化的方法


编辑

您可以使用类似于onCommit我上面解释的方法,或者如果您使用的是SwiftUI 2.0,您可以观察.onChange修饰符的变化(如果实际值从SwiftUI侧面发生变化),例如:

struct ContentView: View {
    @State var text: String = ""

    var body: some View {
        TextView(text: $text)
            .onChange(of: text) { value in
                print("text now: " + text)
            }
    }
}

更新实际@Binding值:

您需要通过text在以下UIKit位置实现此功能来更新侧边coordinator

func textViewDidChange(_ textView: UITextView) {
    parent.text = textView.text
}

然后实际绑定的变量在 textField 的文本更改事件上得到更新。


邦斯

使用此方法,您还可以将配置步骤转发到SwiftUI旁边。所以重构后的完整工作代码如下:

struct ContentView: View {
    @State var text: String = ""

    var body: some View {
        TextView(text: $text) { // Configuring the text field
            $0.font = UIFont(name: "HelveticaNeue", size: 16)
            $0.isScrollEnabled = true
            $0.isEditable = true
            $0.isUserInteractionEnabled = true
            $0.backgroundColor = UIColor(white: 0.0, alpha: 0.00)
            $0.textColor = UIColor.black
        }

        onCommit: { // Detecting the commit
            print("Committed with text: " + text)
        }

        .onChange(of: text) { value in // The native way to detect changes of a State
            print("text now: " + text)
        }
    }
}

struct TextView: UIViewRepresentable {
    @Binding var text: String

    var configurate: (UITextView) -> ()
    var onCommit: ()->()

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UITextView {
        let myTextView = UITextView()
        configurate(myTextView) // Forwarding the configuring step
        myTextView.delegate = context.coordinator
        return myTextView
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
    }

    class Coordinator: NSObject, UITextViewDelegate {
        var parent: TextView

        init(_ uiTextView: TextView) {
            self.parent = uiTextView
        }

        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            if (text == "\n") {
                textView.resignFirstResponder()
                parent.onCommit() // Execute the passed `onCommit` method here
            }
            return true
        }

        func textViewDidChange(_ textView: UITextView) {
            parent.text = textView.text // Update the actual variable
        }
    }
}
于 2020-09-01T20:54:57.360 回答