How to set Keyboard type of TextField in SwiftUI?

KeyboardSwiftuiIos13

Keyboard Problem Overview


I can't seem to find any information or figure out how to set the keyboard type on a TextField for SwiftUI. It would also be nice to be able to enable the secure text property, to hide passwords etc.

This post shows how to "wrap" a UITextField, but I'd rather not use any UI-controls if I don't have to. https://stackoverflow.com/questions/56507839/how-to-make-textfield-become-first-responder

Anyone have any ideas how this can be done without wrapping an old school UI control?

Keyboard Solutions


Solution 1 - Keyboard

To create a field where you can enter secure text you can use SecureField($password)

https://developer.apple.com/documentation/swiftui/securefield

If you want to set the contentType of an textField to eg. .oneTimeCode you can do it like this. Also works with keyboardType

TextField($code)
    .textContentType(.oneTimeCode)
    .keyboardType(.numberPad)

Solution 2 - Keyboard

We no longer need to use hacks. Beta 5 has brought a new modifier to set the keyboard type. For example, to use a number pad:

.keyboardType(.numberPad)

There's also autocapitalization() and an EnvironmentValue disableAutocorrection.

Solution 3 - Keyboard

To set TextField's keyboard type you need to add modifier .keyboardType().

TextField(placeHolder, text: "your text here")
    .keyboardType(.numberPad)

Solution 4 - Keyboard

Set .keyboardType(.numberPad) on the TextField. Simple!

Solution 5 - Keyboard

The following wraps a UITextField class called UIKitTextField using UIViewRepresentable. The keyboard type is set to .decimalPad but could be set to any valid keyboard type.

//  UIKitTextField.swift

import UIKit

class UIKitTextField: UITextField, UITextFieldDelegate {

  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)!
    delegate = self
  }
  
  required override init(frame: CGRect) {
    super.init(frame: frame)
    delegate = self
    self.setContentHuggingPriority(.defaultHigh, for: .vertical)
  }
}

In the ContentView.Swift I created two TextFields. The first is the wrapped UIKit UITextField and the second is the SwiftUI TextField. The data binding is the same so each will display the same text as it is entered.

// ContentView.Swift

import SwiftUI
import UIKit

struct MyTextField : UIViewRepresentable {
  
  @Binding var myText: String
  
  func makeCoordinator() -> MyTextField.Coordinator {
    return Coordinator(text: $myText)
  }
  
  class Coordinator: NSObject {
    @Binding var text: String
    init(text: Binding<String>) {
      $text = text
    }

    @objc func textFieldEditingChanged(_ sender: UIKitTextField) {
      self.text = sender.text ?? ""
    }
  }
  
  func makeUIView(context: Context) -> UIKitTextField {
    
    let myTextField = UIKitTextField(frame: .zero)
    
    myTextField.addTarget(context.coordinator, action: #selector(Coordinator.textFieldEditingChanged(_:)), for: .editingChanged)
    
    myTextField.text = self.myText
    myTextField.placeholder = "placeholder"
    myTextField.borderStyle = .roundedRect
    myTextField.keyboardType = .decimalPad
    
    return myTextField
  }
  
  func updateUIView(_ uiView: UIKitTextField,
                    context: Context) {
    uiView.text = self.myText
  }
  
}


struct MyTextFieldView: View {
  @State var myText: String = "Test"
  var body: some View {
    VStack {
      MyTextField(myText: $myText)
        .padding()
      TextField($myText)
        .textFieldStyle(.roundedBorder)
        .padding()
    }
  }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
  static var previews: some View {
    Group{
      MyTextFieldView().previewLayout(.sizeThatFits)
      MyTextFieldView().previewDevice("iPhone Xs")
    }
  }
}
#endif

Solution 6 - Keyboard

Xcode 13 - iOS & WatchOS App

if you are making a WatchOS app, at the same time as an iOS app you need to add condition for OS check like in code below

           #if os(iOS)
            TextField(placeHolder, text: $text)
                .keyboardType(.numbersAndPunctuation)
            #endif

Solution 7 - Keyboard

> I'm the dev that answered that post - there's no official way to do so > at the moment. Your best bet at the moment is to wrap UITextField – Matteo Pacini

That sums it up, guess we are stuck with wrapping UITextField for now.

Solution 8 - Keyboard

This works for me:

import UIKit
import SwiftUI

class UIKitTextField: UITextField, UITextFieldDelegate {
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        delegate = self
    }
    
    required override init(frame: CGRect) {
        super.init(frame: frame)
        delegate = self
        self.setContentHuggingPriority(.defaultHigh, for: .vertical)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        resignFirstResponder()
        return true
    }
    
}

struct UBSTextField : UIViewRepresentable {
    
    @Binding var myText: String
    let placeHolderText: String
    
    func makeCoordinator() -> UBSTextField.Coordinator {
        return Coordinator(text: $myText)
    }
    
    class Coordinator: NSObject {
        var textBinding: Binding<String>
        init(text: Binding<String>) {
            self.textBinding = text
        }
        
        @objc func textFieldEditingChanged(_ sender: UIKitTextField) {
            self.textBinding.wrappedValue = sender.text ?? ""
        }
    }
    
    func makeUIView(context: Context) -> UIKitTextField {
        
        let textField = UIKitTextField(frame: .zero)
        
        textField.addTarget(context.coordinator, action: #selector(Coordinator.textFieldEditingChanged(_:)), for: .editingChanged)
        
        textField.text = self.myText
        textField.placeholder = self.placeHolderText
        textField.borderStyle = .none
        textField.keyboardType = .asciiCapable
        textField.returnKeyType = .done
        textField.autocapitalizationType = .words
        textField.clearButtonMode = .whileEditing
        
        return textField
    }
    
    func updateUIView(_ uiView: UIKitTextField,
                      context: Context) {
        uiView.text = self.myText
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAaron BertschView Question on Stackoverflow
Solution 1 - KeyboardViktor GardartView Answer on Stackoverflow
Solution 2 - KeyboardkontikiView Answer on Stackoverflow
Solution 3 - KeyboardRohit MakwanaView Answer on Stackoverflow
Solution 4 - KeyboardTejasView Answer on Stackoverflow
Solution 5 - KeyboarddwittView Answer on Stackoverflow
Solution 6 - KeyboardDi_NerdView Answer on Stackoverflow
Solution 7 - KeyboardAaron BertschView Answer on Stackoverflow
Solution 8 - KeyboardjeffbaileyView Answer on Stackoverflow