Reputation: 641
This code works great, just as it should. isFocused reflects the focus state of the text field, and pressing the Button drops the keyboard.
struct ContentView: View {
@State private var textInput = ""
@FocusState private var isFocused: Bool
var body: some View {
VStack {
TextField("Enter text", text: $textInput)
.focused($isFocused)
Button("Submit") {
isFocused = false
}
}
}
}
However, putting the TextField instead a ScrollView results in @FocusState NOT working. When the button is tapped, "Dismiss" is printed but the keyboard does not resign.
struct ContentView: View {
@State private var textInput = ""
@FocusState private var isFocused: Bool
var body: some View {
ScrollView(.vertical) {
TextField("Enter text", text: $textInput)
.focused($isFocused)
Button("Dismiss") {
isFocused = false
print("Dismiss")
}
}
}
}
Why is this the case? And how could this be fixed?
Upvotes: 2
Views: 1298
Reputation: 121
Experiencing the same still with Xcode 15 beta 6.
A temporary workaround (though not ideal) is to replace your ScrollView with a VStack inside a List with listStyle set to plain, row separators set to hidden and row insets as (0, 0, 0, 0).
i.e.
struct ContentView: View {
@State private var textInput = ""
@FocusState private var isFocused: Bool
var body: some View {
List {
VStack {
TextField("Enter text", text: $textInput)
.focused($isFocused)
Button("Dismiss") {
isFocused = false
print("Dismiss")
}
}
.listRowSeparator(.hidden)
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.padding(.horizontal)
}
.listStyle(.plain)
}
}
This should produce identical results to a ScrollView. To avoid repeating the workaround pattern, here's a quick backporting wrapper.
struct BackportScrollView<Content: View>: View {
var content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) { self.content = content }
var body: some View {
if #available(iOS 17.0, *) {
List {
VStack { content() }
.listRowSeparator(.hidden)
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.padding(.horizontal)
}
.listStyle(.plain)
} else {
ScrollView(.vertical) { content() }
}
}
}
You can use this like so:
struct ContentView: View {
@State private var textInput = ""
@FocusState private var isFocused: Bool
var body: some View {
BackportScrollView {
TextField("Enter text", text: $textInput)
.focused($isFocused)
Button("Dismiss") {
isFocused = false
print("Dismiss")
}
}
}
}
Upvotes: 0