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

如何在Observable类型中使用SwiftUI的FocusState?

在SwiftUI Observable类型中管理FocusState的解决方案

由于@FocusState是SwiftUI视图专属的属性包装器,无法直接在@Observable类中使用,但可以通过以下两种方式将焦点控制逻辑迁移到Observable对象中,实现业务逻辑与视图的分离:

方案一:将FocusState的Binding传递给Observable方法

直接在Observable类的验证方法中接收FocusState的绑定对象,完成焦点设置:

修改后的FormState类

@Observable class FormState {
    var name = ""
    var answer = ""
    var showAlert = false
    var alertMessage = ""
    
    // 接收FocusState的Binding参数,在方法内控制焦点
    func validateForm(focus: Binding<Field?>) -> Bool {
        if name.isEmpty {
            focus.wrappedValue = .name
            alertMessage = "请输入你的名字。"
            showAlert = true
            return false
        } else if answer.isEmpty {
            focus.wrappedValue = .answer
            alertMessage = "请给出你的答案。"
            showAlert = true
            return false
        } else if answer != "Rush" {
            focus.wrappedValue = .answer
            alertMessage = "错误!再试一次!\n(提示:不是Metallica)"
            showAlert = true
            return false
        } else {
            alertMessage = "摇滚起来,\(name)!\n你答对了!"
            showAlert = true
            return true
        }
    }
    
    enum Field: Hashable, Codable {
        case name, answer
    }
}

修改后的视图代码

struct ObservableVersion: View {
    @Environment(FormState.self) var state
    @FocusState private var focus: FormState.Field?

    var body: some View {
        Form {
            @Bindable var state = state
            
            TextField("姓名", text: $state.name)
                .focused($focus, equals: .name)
            
            Section("世界上最好的金属乐队是?") {
                TextField("乐队名称", text: $state.answer)
                    .focused($focus, equals: .answer)
            }
            
            Button("确认") {
                // 将FocusState的绑定传递给Observable的验证方法
                _ = state.validateForm(focus: $focus)
            }
            .alert(state.alertMessage, isPresented: $state.showAlert) {
                Button("确定") {}
            }
        }
    }
}

#Preview {
    ObservableVersion()
        .environment(FormState())
}

方案二:在Observable中维护焦点状态,与View的FocusState双向同步

在Observable类中新增一个存储焦点状态的属性,通过视图的onChange实现与@FocusState的双向同步:

修改后的FormState类

@Observable class FormState {
    var name = ""
    var answer = ""
    var showAlert = false
    var alertMessage = ""
    // 在Observable中维护焦点状态
    var focusField: Field? = nil
    
    enum Field: Hashable, Codable {
        case name, answer
    }
    
    func validateForm() -> Bool {
        if name.isEmpty {
            focusField = .name
            alertMessage = "请输入你的名字。"
            showAlert = true
            return false
        } else if answer.isEmpty {
            focusField = .answer
            alertMessage = "请给出你的答案。"
            showAlert = true
            return false
        } else if answer != "Rush" {
            focusField = .answer
            alertMessage = "错误!再试一次!\n(提示:不是Metallica)"
            showAlert = true
            return false
        } else {
            alertMessage = "摇滚起来,\(name)!\n你答对了!"
            showAlert = true
            return true
        }
    }
}

修改后的视图代码

struct ObservableVersion: View {
    @Environment(FormState.self) var state
    @FocusState private var focus: FormState.Field?

    var body: some View {
        Form {
            @Bindable var state = state
            
            TextField("姓名", text: $state.name)
                .focused($focus, equals: .name)
            
            Section("世界上最好的金属乐队是?") {
                TextField("乐队名称", text: $state.answer)
                    .focused($focus, equals: .answer)
            }
            
            Button("确认") {
                _ = state.validateForm()
            }
            .alert(state.alertMessage, isPresented: $state.showAlert) {
                Button("确定") {}
            }
        }
        // 同步Observable的焦点状态到View的FocusState
        .onChange(of: state.focusField) { _, newValue in
            focus = newValue
        }
        // 可选:同步View的焦点变化回Observable,确保状态一致
        .onChange(of: focus) { _, newValue in
            state.focusField = newValue
        }
    }
}

#Preview {
    ObservableVersion()
        .environment(FormState())
}

方案对比

  • 方案一:实现简单,无需额外同步逻辑,适合单个视图控制焦点的场景。
  • 方案二:让Observable完全掌控焦点状态,适合需要在多个视图或业务逻辑中控制焦点的复杂场景。

内容的提问来源于stack exchange,提问作者Curious Jorge

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:10:06