用户在 SwiftUI 中单击键盘上的删除按钮时的操作

Action when user click on the delete button on the keyboard in SwiftUI

我尝试 运行 当用户在尝试修改文本字段时单击键盘上的删除按钮时的功能。

我该怎么做?

是的,这是可能的,但是它需要子类化 UITextField 并创建您自己的 UIViewRepresentable

这个答案是基于 Costantino Pistagna 在他 medium article 中所做的出色工作,但我们需要做更多的工作。

首先我们需要创建UITextField的子类,这也应该符合UITextFieldDelegate协议。

class WrappableTextField: UITextField, UITextFieldDelegate {
    var textFieldChangedHandler: ((String)->Void)?
    var onCommitHandler: (()->Void)?
    var deleteHandler: (() -> Void)?

    override func deleteBackward() {
        super.deleteBackward()
        deleteHandler?()
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if let nextField = textField.superview?.superview?.viewWithTag(textField.tag + 1) as? UITextField {
            nextField.becomeFirstResponder()
        } else {
            textField.resignFirstResponder()
        }
        return false
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if let currentValue = textField.text as NSString? {
            let proposedValue = currentValue.replacingCharacters(in: range, with: string)
            textFieldChangedHandler?(proposedValue as String)
        }
        return true
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        onCommitHandler?()
    }
}

因为我们正在创建自己的 TextField 实现,所以我们需要三个可用于回调的函数。

  1. textFieldChangeHandler 这将在文本 属性 更新时调用,并允许我们更改与我们的 Textfield.
  2. 关联的状态值
  3. onCommitHandler 这将在我们完成 TextField
  4. 编辑后调用
  5. deleteHandler 当我们执行删除操作时会调用它。

上面的代码显示了这些是如何使用的。您特别感兴趣的部分是 override func deleteBackward(),通过覆盖它,我们可以在按下删除按钮时挂钩并对其执行操作。根据您的用例,您可能希望在调用 super.

之前调用 deleteHandler

接下来我们需要创建 UIViewRepresentable.

struct MyTextField: UIViewRepresentable {
    private let tmpView = WrappableTextField()

    //var exposed to SwiftUI object init
    var tag:Int = 0
    var placeholder:String?
    var changeHandler:((String)->Void)?
    var onCommitHandler:(()->Void)?
    var deleteHandler: (()->Void)?

    func makeUIView(context: UIViewRepresentableContext<MyTextField>) -> WrappableTextField {
        tmpView.tag = tag
        tmpView.delegate = tmpView
        tmpView.placeholder = placeholder
        tmpView.onCommitHandler = onCommitHandler
        tmpView.textFieldChangedHandler = changeHandler
        tmpView.deleteHandler = deleteHandler
        return tmpView
    }

    func updateUIView(_ uiView: WrappableTextField, context: UIViewRepresentableContext<MyTextField>) {
        uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
        uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
    }
}

这是我们创建 WrappableTextField 的 SwiftUI 版本的地方。我们创建 WrappableTextField 及其属性。在 makeUIView 函数中,我们分配这些属性。最后在 updateUIView 中,我们设置了内容拥抱属性,但您可以选择不这样做,这实际上取决于您的用例。

最后我们可以创建一个小的工作示例。

struct ContentView: View {

    @State var text = ""

    var body: some View {
        MyTextField(tag: 0, placeholder: "Enter your name here", changeHandler: { text in
            // update the state's value of text
            self.text = text
        }, onCommitHandler: {
            // do something when the editing finishes
            print("Editing ended")
        }, deleteHandler: {
            // do something here when you press delete
            print("Delete pressed")
        })
    }
}