Swiftui: How to Make Textfield Become First Responder

SwiftUI: How to make TextField become first responder?

iOS 15.0+

macOS 12.0+,

Mac Catalyst 15.0+,

tvOS 15.0+,

watchOS 8.0+

Use focused(_:) if you have a single TextField.

focused(_:)

Modifies this view by binding its focus state to the given Boolean state value.

struct NameForm: View {

@FocusState private var isFocused: Bool

@State private var name = ""

var body: some View {
TextField("Name", text: $name)
.focused($isFocused)

Button("Submit") {
if name.isEmpty {
isFocued = true
}
}
}
}

Use focused(_:equals:) should you have multiple TextFields.

focused(_:equals:)

Modifies this view by binding its focus state to the given state value.

struct LoginForm: View {
enum Field: Hashable {
case usernameField
case passwordField
}

@State private var username = ""
@State private var password = ""
@FocusState private var focusedField: Field?

var body: some View {
Form {
TextField("Username", text: $username)
.focused($focusedField, equals: .usernameField)

SecureField("Password", text: $password)
.focused($focusedField, equals: .passwordField)

Button("Sign In") {
if username.isEmpty {
focusedField = .usernameField
} else if password.isEmpty {
focusedField = .passwordField
} else {
handleLogin(username, password)
}
}
}
}
}

SwiftUI Documentation

  • focused(_:)
  • focused(_:equals:)
  • @FocusState


Update

I tested this in xCode version 13.0 beta 5 (13A5212g). It works

Autofocus TextField programmatically in SwiftUI

iOS 15

There is a new wrapper called @FocusState that controls the state of the keyboard and the focused keyboard ('aka' firstResponder).

Become First Responder ( Focused )

If you use a focused modifier on the text fields, you can make them become focused, for example, you can set the focusedField property in the code to make the binded textField become active:

Sample Image

Resign first responder ( Dismiss keyboard )

or dismiss the keyboard by setting the variable to nil:

Sample Image

Don't forget to watch the Direct and reflect focus in SwiftUI session from WWDC2021



iOS 13 and 14 (and 15)

Old but working:

Simple wrapper struct - Works like a native:

Note that Text binding support added as requested in the comments

struct LegacyTextField: UIViewRepresentable {
@Binding public var isFirstResponder: Bool
@Binding public var text: String

public var configuration = { (view: UITextField) in }

public init(text: Binding<String>, isFirstResponder: Binding<Bool>, configuration: @escaping (UITextField) -> () = { _ in }) {
self.configuration = configuration
self._text = text
self._isFirstResponder = isFirstResponder
}

public func makeUIView(context: Context) -> UITextField {
let view = UITextField()
view.addTarget(context.coordinator, action: #selector(Coordinator.textViewDidChange), for: .editingChanged)
view.delegate = context.coordinator
return view
}

public func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
switch isFirstResponder {
case true: uiView.becomeFirstResponder()
case false: uiView.resignFirstResponder()
}
}

public func makeCoordinator() -> Coordinator {
Coordinator($text, isFirstResponder: $isFirstResponder)
}

public class Coordinator: NSObject, UITextFieldDelegate {
var text: Binding<String>
var isFirstResponder: Binding<Bool>

init(_ text: Binding<String>, isFirstResponder: Binding<Bool>) {
self.text = text
self.isFirstResponder = isFirstResponder
}

@objc public func textViewDidChange(_ textField: UITextField) {
self.text.wrappedValue = textField.text ?? ""
}

public func textFieldDidBeginEditing(_ textField: UITextField) {
self.isFirstResponder.wrappedValue = true
}

public func textFieldDidEndEditing(_ textField: UITextField) {
self.isFirstResponder.wrappedValue = false
}
}
}

Usage:

struct ContentView: View {
@State var text = ""
@State var isFirstResponder = false

var body: some View {
LegacyTextField(text: $text, isFirstResponder: $isFirstResponder)
}
}

Bonus: Completely customizable

LegacyTextField(text: $text, isFirstResponder: $isFirstResponder) {
$0.textColor = .red
$0.tintColor = .blue
}

SwiftUI - making a textfield inside a view be the first responder on touch to that view

Using a custom TextField like the one from Matteo Pacini

you can do something like this:

struct CustomTextField1: UIViewRepresentable {
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
var didBecomeFirstResponder = false
init(text: Binding<String>) {
_text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
}
@Binding var text: String
var isFirstResponder: Bool = false
func makeUIView(context: UIViewRepresentableContext<CustomTextField1>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func makeCoordinator() -> CustomTextField1.Coordinator {
return Coordinator(text: $text)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField1>) {
uiView.text = text
if isFirstResponder && !context.coordinator.didBecomeFirstResponder {
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
}

struct ContentView : View {
@State var text: String = ""
@State var isEditing = false
var body: some View {
CustomTextField1(text: $text, isFirstResponder: isEditing)
.frame(width: 300, height: 50)
.background(Color.red)
.onTapGesture {
isEditing.toggle()
}
}
}

It's a bit complex, but should get the work done. As for a pure SwiftUI answer, it's currently unavailable.



Related Topics



Leave a reply



Submit