Home > Enterprise >  SwiftUI: How to prevent `onSubmit` on TextField from hiding keyboard?
SwiftUI: How to prevent `onSubmit` on TextField from hiding keyboard?

Time:09-08

This simple TextField might be part of a chat feature, and I would like to be able to send chat messages when I press the keyboard button "send".

(Imagine in this chat I don't need to allow users to enter newline, by overriding the return key, to be send with the submitLabel(.send) view modifier.)

TextField(
    "Chat...",
    text: $draft
)
.submitLabel(.send)
.onSubmit {
    if !draft.isEmpty {
        sendMessage(draft: draft)
    }
}

However, this will hide the keyboard, and I would like to know:

is there any way to prevent the keyboard from hiding when I press send??

I know how to refocus the field, I can do that with @FocusState but that still results in a hide keyboard animation starting which then aborts, so looks glithy.

CodePudding user response:

Here is something you can work with. During .onSubmit set the focusedField back to .field, and use .transaction to capture the current transaction and set the animation to nil:

struct ContentView: View {
    enum FocusField: Hashable {
      case field
    }
    
    @State private var draft = "Hello, world"
    @FocusState private var focusedField: FocusField?

    var body: some View {
        TextField(
            "Chat...",
            text: $draft
        )
        .submitLabel(.send)
        .focused($focusedField, equals: .field)
        .onSubmit {
            focusedField = .field
            if !draft.isEmpty {
                sendMessage(draft: draft)
            }
        }
        .transaction { t in
            t.animation = nil
        }
    }
    
    func sendMessage(draft: String) {
        print("The message: \(draft)")
    }
    
}

CodePudding user response:

It is possible to prevent keyboard hiding using a somewhat "hacky" solution, combing re-focus of field together with disable animation.

struct ChatView {
    enum Field: String, Hashable {
        case chat
    }
    @State var draft = ""
    @FocusState var focusedField: Field?

    var body: some View {
        VStack {
            // messages view omitted
            TextField(
                "Chat...",
                text: $draft
            )
            .submitLabel(.send)
            .onSubmit {
                if !draft.isEmpty {
                    sendMessage()
                    // We just lost focus because "return" key was pressed
                    // we re-fucus
                    focusedField = .chat
                }
            }

            Button("Send") {
                sendMessage()
            }
        } 
        // Prevent hacky keyboard hide animation
        .transaction { $0.animation = nil }
    }    

    func sendMessage() {
       // impl omitted, sending message `draft` using some dependency.
    }
}

  • Related