Да, это возможно, однако для этого необходимо создать подкласс UITextField
и создать свой собственный UIViewRepresentable
Этот ответ основан на фантастической работе, проделанной Костантино Пистанья в его статье среднего но нам нужно проделать немного больше работы.
Во-первых, нам нужно создать наш подкласс 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
, нам нужны три функции, которые мы можем использовать для обратных вызовов.
textFieldChangeHandler
это будет вызвано при обновлении свойства текста и позволит нам изменить значение состояния, связанное с нашим Textfield
. onCommitHandler
, которое будет вызвано, когдамы закончили редактирование нашего TextField
deleteHandler
, которое будет вызываться при выполнении действия по удалению.
Приведенный выше код показывает, как они используются. Часть, которая вас особенно интересует, - это override func deleteBackward()
, переопределив это, мы можем подключиться при нажатии кнопки удаления и выполнить над ней действие. В зависимости от вашего варианта использования, вы можете захотеть, чтобы deleteHandler
вызывался до того, как вы вызовете super
.
Далее нам нужно создать 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)
}
}
ThisЗдесь мы создаем нашу версию SwiftUI нашего WrappableTextField
. Мы создаем наш 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")
})
}
}