英文:
SwiftUI @FocusState not working in ScrollView
问题
这段代码运行得很好,正如它应该的那样。isFocused 反映了文本字段的焦点状态,按下按钮会隐藏键盘。
但是,将 TextField 放在 ScrollView 中会导致 @FocusState 不起作用。当点击按钮时,会打印出 "Dismiss",但键盘不会隐藏。
为什么会出现这种情况?以及如何修复?
英文:
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?
答案1
得分: 3
我目前在Xcode 15 beta 4上遇到了完全相同的问题,相同的代码在Xcode 14上运行得很好。已提交了一个错误报告,希望在未来的版本中能解决这个问题。
英文:
I'm currently experiencing the exact same problem on Xcode 15 beta 4, the same code works just fine in Xcode 14. Filed a bug report and hopefully it gets resolved in future versions.
答案2
得分: 0
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")
}
}
}
}
英文:
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")
}
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论