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:
Resign first responder ( Dismiss keyboard )
or dismiss the keyboard by setting the variable to nil
:
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
How to Check If a String Contains Another String in Swift
Convert String to Date in Swift
Why Is Swift Compile Time So Slow
How to Unwrap an Optional Value from Any Type
How to Set Layer Cornerradius For Only Bottom-Left, Bottom-Right, and Top-Left Corner
Extra Arguments At Positions #11, #12 in Call Swiftui
How to Make a Swiftui List Scroll Automatically
What's the Cleanest Way of Applying Map() to a Dictionary in Swift
Xcode 8 Beta 3 Use Legacy Swift Issue
Initialize @Stateobject With a Parameter in Swiftui
Custom Back Button For Navigationview'S Navigation Bar in Swiftui
Closure With Generic Parameters
What Sorting Algorithm Does Swift Implement For Its Standard Library