如何添加 onCommit、isEditing 以及自定义绑定到自定义 textview 的能力?

Posted

技术标签:

【中文标题】如何添加 onCommit、isEditing 以及自定义绑定到自定义 textview 的能力?【英文标题】:How to add onCommit, isEditing, and ability to have a custom binding to a custom textview? 【发布时间】:2020-08-30 18:25:25 【问题描述】:

提供以下 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
    
    )

【问题讨论】:

【参考方案1】:

onCommit

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

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

您需要通过在coordinator 中实现此功能来更新UIKit 端的text

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
        
    

【讨论】:

谢谢!很详细的回答 谢谢,这很有帮助

以上是关于如何添加 onCommit、isEditing 以及自定义绑定到自定义 textview 的能力?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - 如何在另一个视图中响应 TextField onCommit?

Angular 6 中的剑道网格:isEditing:如何?

当isedit !=1时,在更新时触发,防止更新。

以编程方式 ComboBox VirtualizingStackPanel WPF

Xcode 4.3 在哪里实现isEditable、isSelectable?

Next.js:当每个标签检查其 isEdit 状态是真还是假时,如何使只有一个输入字段可内联编辑