You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让传递给.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:28:17