3

I'm trying to have a vertically growing TextField in `SwiftUI but also have the software keyboard have a custom submission method.

This uses the new functionality of iOS 16's TextFields being able to take an axis as an argument for which way it should grow. See the docs here: https://developer.apple.com/documentation/swiftui/textfield/init(_:text:axis:)-8rujz.

Here's a sample ContentView showing the setup.

struct ContentView: View {

    @State var message: String = ""
    var body: some View {
        
        VStack {
            Text("Try to submit this using the blue send button on the software keyboard")
            TextField("Placeholder", text: $message, axis: .vertical)
                .onSubmit {
                    print("submission!")
                }
            .submitLabel(.send)
        }
    }
}

When you run this, you can see the TextField properly grows vertically, but even when you have a custom submission label, pressing the blue "send" button in the software keyboard on iOS just inserts a newline, rather than firing the .onSubmit

When using a hardware keyboard, pressing the return does run the code in .onSubmit, so this seemingly just a limitation of the software keyboard.

3 Answers3

2

I've applied the excellent advice from this post to your question. Would this work for you?

struct ContentView: View {

@State var message: String = ""
var body: some View {
    
    VStack {
        Text("Try to submit this using the blue send button on the software keyboard")
        TextField("Placeholder", text: $message, axis: .vertical)
            .submitLabel(.send)
            .onChange(of: message) { newValue in
                guard let newValueLastChar = newValue.last else { return }
                if newValueLastChar == "\n" {
                    message.removeLast()
                    print("submission!")
                    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
                }
            }
                            
    }
}

}

ej5607
  • 309
  • 2
  • 12
2

I modified previous solutions, because in my case they led to TextField's jumping back and forth, adding and instantly removing a new line after hitting return (or done). If you experience similar behaviour, I combined previous solutions with this idea, and it helped. So, basically, you need to find out whether "\n" was inserted somewhere, and switch FocusState before message itself changes.

struct ContentView: View {

    @State var message: String = ""
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack {
            TextField("Placeholder",
                      text: Binding(
                        get: { message },
                        set:
                            { (newValue, _) in
                                if let _ = newValue.lastIndex(of: "\n") {
                                    isFocused = false
                                } else {
                                    message = newValue
                                }
                            }
                      ), axis: .vertical)
                .submitLabel(.done)
                .focused($isFocused)
        }
    }
}
1

ej5607's answer won't work if the user is editing partway through the string and hits the Send button. I've modified it to fix that and also use the @FocusState rather than calling in to UIApplication.

struct ContentView: View {
    
    @State var message: String = ""
    enum Field: Int, Hashable {
        case message
    }
    @FocusState private var focusedField: Field?

    var body: some View {
    
        VStack {
            Text("Try to submit this using the blue send button on the software keyboard")
            TextField("Placeholder", text: $message, axis: .vertical)
                .submitLabel(.send)
                .focused($focusedField, equals: .message)
                .onChange(of: message) { newValue in
                    if let newLineIndex = message.lastIndex(of: "\n") {
                        message.remove(at: newLineIndex)
                        print("submission!")
                        focusedField = nil
                    }
                }
            }
        }
    }
}
SeanR
  • 7,899
  • 6
  • 27
  • 38