如何让传递给.sheet中TextField的@FocusState Binding生效?
解决SwiftUI中Sheet子视图绑定父视图@FocusState时.onChange不触发的问题
问题核心在于**@FocusState是和当前视图层级的焦点管理器绑定的**,而Sheet会创建一个独立的视图层级,父视图的@FocusState无法跨层级与子视图的TextField建立正确关联,导致焦点变化无法触发.onChange回调。
解决方案:子视图内部管理@FocusState,同步状态到父视图Binding
让子视图自己维护焦点状态,通过传入的Binding将状态同步回父视图,既保证焦点能正常被跟踪,也能让父视图获取到焦点状态。
修改后的代码如下:
struct TestView: View { @State private var sheetIsPresented: Bool = false @State private var textFieldIsFocused: Bool // 替换为@State,不再依赖父视图@FocusState var body: some View { Button("Hello") { sheetIsPresented = true } .buttonStyle(.borderedProminent) .sheet(isPresented: $sheetIsPresented) { TestViewSheet(textFieldIsFocused: $textFieldIsFocused) } } } struct TestViewSheet: View { @State private var userInput: String = "" @Binding var textFieldIsFocused: Bool @FocusState private var localFocused: Bool // 子视图独立维护焦点状态 var body: some View { HStack { Text("Name:") TextField("Enter name", text: $userInput) .focused($localFocused) .onChange(of: localFocused) { newValue in textFieldIsFocused = newValue // 将焦点状态同步到父视图Binding print("textFieldIsFocused: \(newValue)") } } .onAppear { // 若父视图需要初始控制焦点,同步父状态到子视图 localFocused = textFieldIsFocused } } }
复杂场景方案:用ObservableObject共享焦点状态
如果需要在多个视图间共享焦点状态,可以将状态包装在ObservableObject中,通过环境传递:
class FocusManager: ObservableObject { @Published var textFieldIsFocused: Bool = false } struct TestView: View { @State private var sheetIsPresented: Bool = false @StateObject private var focusManager = FocusManager() var body: some View { Button("Hello") { sheetIsPresented = true } .buttonStyle(.borderedProminent) .sheet(isPresented: $sheetIsPresented) { TestViewSheet() .environmentObject(focusManager) } } } struct TestViewSheet: View { @State private var userInput: String = "" @EnvironmentObject private var focusManager: FocusManager @FocusState private var localFocused: Bool var body: some View { HStack { Text("Name:") TextField("Enter name", text: $userInput) .focused($localFocused) .onChange(of: localFocused) { newValue in focusManager.textFieldIsFocused = newValue print("textFieldIsFocused: \(newValue)") } } .onAppear { localFocused = focusManager.textFieldIsFocused } } }
关键说明
- Sheet作为独立视图层级,拥有自己的焦点上下文,父视图的@FocusState无法直接作用于子视图的TextField。
- 子视图必须通过自身的@FocusState管理焦点,再将状态同步到外部Binding或ObservableObject,才能保证状态变化被正确捕获。
内容的提问来源于stack exchange,提问作者Ser Pounce
相关产品推荐
相关产品推荐

