0

I am trying to change the keyboard type of a single TextField dynamically. That is, I have something like this:

struct ContentView: View {

  @Binding var keyboardType: UIKeyboardType
  @State var searchText = ""

  var body: some View {
    TextField("placeholder", text: $searchText).keyboardType(keyboardType)
  }
}

Now, dynamically, I would like the keyboard to change from one keyboard style to the other, depending on what keyboardType is. However, what I've found is that keyboardType changes, but the soft keyboard doesn't. Rather, the keyboard stays the same, and only after I dismiss the keyboard and bring it back up, does it show something different.

I see that there is a way to wrap UITextField so that the keyboard updates dynamically. But I was wondering/hoping there'd be a way to do this in SwiftUI. Perhaps there's a way to access UITextView's reloadInputViews() method? Any help would be appreciated.

2 Answers 2

1

You can use @FocusState – disable focus, change the keyboard, then focus again:

struct ContentView: View {
    
    @State var mykeyboard = UIKeyboardType.numberPad
    @State var searchText = ""
    
    @FocusState var focus: Bool
    
    var body: some View {
        
        VStack {
            Divider()
            HStack {
                TextField("placeholder", text: $searchText)
                    .keyboardType(mykeyboard)
                    .focused($focus)
                
                Button("Submit") {
                    focus = false
                }
            }
            Divider()
            
            HStack {
                Button("Numbers") {
                    focus = false
                    mykeyboard = .numberPad
                    focus = true
                }
                Button("EMail") {
                    focus = false
                    mykeyboard = .emailAddress
                    focus = true
                }.padding()
                Button("Alphabet") {
                    focus = false
                    mykeyboard = .alphabet
                    focus = true
                }
            }

        }
        .padding()
        .buttonStyle(.bordered)
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

I know this thread is a few years old, but I had the same problem and the focus workaround doesn't seem to work that great anymore.

As you've said, it's necessary to call reloadInputViews on the UITextField.
It's possible to use UIApplication.sendAction(_:to:from:for:), which sends the action to the first responder when to/target is nil.

Because the state is not valid until after the view's body is evaluated, it's necessary to wrap it in a dispatch async call.

So taking the solution from @ChrisR as base, you can achieve the keyboard change using the following snippet:

Button("Numbers") {
    mykeyboard = .numberPad
    DispatchQueue.main.async {
        UIApplication.shared.sendAction(#selector(UIResponder.reloadInputViews), to: nil, from: nil, for: nil)
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.