Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent keyboard for TextField from dismissing after a [Return] but need to detect a [Return] keypress too

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.

like image 315
Barrrdi Avatar asked Sep 20 '25 04:09

Barrrdi


1 Answers

I work around this by passing whatever action I would usually execute in .onSubmit to the UITextFieldDelegate:

class TextFieldDelegate: NSObject, UITextFieldDelegate {
    
    var shouldReturn: (() -> Bool)?
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        if let shouldReturn = shouldReturn {
            return shouldReturn()
        }
        else {
            return true
        }
    }
}

Then in our SwiftUI view:

import Introspect

struct TestView: View {
    
    enum FocusedField {
        case username, password
    }
    
    @State private var username: String = ""
    @State private var password: String = ""
    
    var usernameFieldDelegate = TextFieldDelegate()
    var passwordFieldDelegate = TextFieldDelegate()
    
    @FocusState private var focusedField: FocusedField?
    
    var body: some View {
        
        VStack {
            
            TextField(text: $username)
                .focused($focusedField, equals: .username)
                .introspectTextField(customize: { textField in
                    
                    usernameFieldDelegate.shouldReturn = {
                        
                        if usernameIsValid() {
                            focusedField = .password
                        }
                        
                        return false
                    }
                    
                    textField.delegate = usernameFieldDelegate
                })
            
            SecureField(text: $password)
                .focused($focusedField, equals: .password)
                .introspectTextField(customize: { textField in
                    
                    passwordFieldDelegate.shouldReturn = {
                        validateAndProceed()
                        
                        return false
                    }
                    
                    textField.delegate = passwordFieldDelegate
                })
        }
    }
    
    func usernameIsValid() -> Bool {
        return true
    }
    
    func validateAndProceed() {}
}
like image 185
Dean L Avatar answered Sep 24 '25 04:09

Dean L