I'm trying to delete all text inside a Text Field when a button to the right of the text field is tapped. When I tap the clear button it behaves as though the text has been cleared. It shows the placeholder text which is set to be shown when the Text Field is cleared. However, the text is still showing 'underneath' the placeholder text. I can delete the typed in text by using the delete key on the keyboard, one character at a time, but clearing all at once should be a quicker option.
I have a UIViewRepresentable for a TextField as below. The reason I'm using a UIViewRepresentable is because I need the keyboard language layout to change languages as required by the user. SwiftUI doesn't currently support this:
struct UITextFieldViewRepresentable: UIViewRepresentable {
@Binding var language: String
@Binding var text: String
var onCommit: (() -> Bool)
init(language: Binding<String>, text: Binding<String>, onCommit: @escaping() -> Bool = { return true }) {
self._language = language
self._text = text
self.onCommit = onCommit
}
func makeUIView(context: Context) -> WordTextField {
let textField = WordTextField(onCommit: onCommit)
textField.language = self.language
textField.textAlignment = .center
textField.font = UIFont.systemFont(ofSize: 15, weight: .regular)
return textField
}
func updateUIView(_ uiView: WordTextField, context: Context) {
uiView.textDidChange = {
text = $0
}
// Change the keyboard language only when uiView.language != self.language
//
if uiView.language != self.language {
uiView.language = self.language
}
}
}
class WordTextField: UITextField, UITextFieldDelegate {
var textDidChange: ((String) -> Void)?
var onCommit: (() -> Bool)
var language: String? {
didSet {
if self.isFirstResponder{
self.resignFirstResponder()
self.becomeFirstResponder()
}
}
}
init(textDidChange: ( (String) -> Void)? = nil, onCommit: @escaping () -> Bool = { return true }, language: String? = nil) {
self.textDidChange = textDidChange
self.onCommit = onCommit
self.language = language
super.init(frame: .zero)
self.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func textFieldDidChangeSelection(_ textField: UITextField) {
textDidChange?(textField.text ?? "")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return onCommit()
}
override var textInputMode: UITextInputMode? {
if let language = self.language {
print("text input mode: \(language)")
for inputMode in UITextInputMode.activeInputModes {
if let inputModeLanguage = inputMode.primaryLanguage, inputModeLanguage == language {
return inputMode
}
}
}
return super.textInputMode
}
}
I call it as below:
@State private var userAnswer: String = ""
@State private var keyboardLanguage: String = ""
@State private var hintColour: Color = .green
@State private var hintDisabled: Bool = false
UITextFieldViewRepresentable(language: $keyboardLanguage, text: Binding<String>(
get: { self.userAnswer },
set: {
self.userAnswer = $0.allowedCharacters(string: $0)
self.enableHint()
}), onCommit: {
checkAnswer()
return true
})
.showClearButton(userAnswer: $userAnswer, hintDisabled: $hintDisabled, hintColour: $hintColour)
The view modifier .showClearButton does not clear the userAnswer text when tapped. Tapping the keyboard delete button clears userAnswer one character at a time.
The view modifier code is below:
extension View {
func showClearButton(userAnswer: Binding<String>, hintDisabled: Binding<Bool>, hintColour: Binding<Color>) -> some View {
self.modifier(TextFieldClearButton(text: userAnswer, hintDisabled: hintDisabled, hintColour: hintColour))
}
}
struct TextFieldClearButton: ViewModifier {
@Binding var text: String
@Binding var hintDisabled: Bool
@Binding var hintColour: Color
func body(content: Content) -> some View {
HStack {
content
if !text.isEmpty {
Button(
action: { self.text = ""; hintDisabled = false; hintColour = Color.systemBlue },
label: {
Image(systemName: "delete.left")
.foregroundColor(Color(UIColor.gray))
.imageScale(.large)
.frame(width: 44, height: 44, alignment: .trailing)
}
)
}
}
}
}
You forgot to set the new text on the
UITextFieldwhich in the case of the clear button is an empty string, fix like this:Also, you could benefit from a
Coordinator here, it works like this: