In short, I’m trying to achieve the Reminders.app interaction when you add an entry, hit [Return] and can then add the next entry immediately (i.e. keyboard does not dismiss, but only does if you hit [Return] on an empty line).
This would be straightforward if it was not for this issue: how can I keep the keyboard opened with @FocusState with SwiftUI without a bounce? (keyboard bounces after a [Return]).
I considered many solutions but the cleanest to keep the keyboard up is to leverage introspect:
class TextFieldKeyboardBehavior: UIView, UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return false
}
}
struct TestView: View {
@State var text: String = ""
var textFieldKeyboardBehavior = TextFieldKeyboardBehavior()
var body: some View {
VStack {
TextField("Title", text: $text)
.introspect(.textField, on: .iOS(.v17)) {
$0.delegate = textFieldKeyboardBehavior
}
.onSubmit {
// code
}
}
}
}
Now the (big!) problem with this approach is that the onSubmit never gets called. If I add an onChange modifier, it is called on every press, but I don’t believe observing value changes here can reliably detect when is the correct moment to actually dismiss the keyboard. I understand I’m effectively disabling [Return] capabilities and so the behaviour should come as no surprise, but then I’m wondering whether there’s another approach leveraging introspect combined with a TextField that enables what I’m after: 1) keyboard doesn’t dismiss on a [Return], and 2) [Return] is always detected.
Here's what I come up with using @FocusState. Enter text in the TextField and hit return. The .onSubmit() will add another TextField and shift its focus without dismissing the keyboard. The keyboard will dismiss when hitting return if the TextField is empty.