iOS 16 UIHostingConfiguration中@FocusState无法更新.wrappedValue问题
解决UIHostingConfiguration中@FocusState无法更新焦点的问题
问题根源
- @FocusState初始化赋值无效:SwiftUI的
@FocusState绑定需在视图进入渲染上下文后才生效,直接在init中设置wrappedValue不会起作用。 - 视图实例重复创建:UIHostingConfiguration每次更新cell配置时,都会重新实例化
TaskView,导致内部@FocusState状态被重置为初始值。 - 单向状态传递缺陷:仅通过参数单向传递
shouldFocus值,无法将TaskView内部的焦点变化同步回父视图,导致状态不一致。
修复方案
方案1:单向同步外部焦点状态
适合仅需父视图控制子视图焦点的场景:
父视图Cell配置代码:
// 父视图维护跟踪焦点任务的状态 @State private var focusedTask: Task? cell.configurationUpdateHandler = { [self] (cell, state) in cell.contentConfiguration = UIHostingConfiguration { TaskView(task: task, shouldFocus: focusedTask == task) } }
修改后的TaskView:
struct TaskView: View { @ObservedObject var task: Task let shouldFocus: Bool // 用私有@FocusState管理内部焦点 @FocusState private var isFocused: Bool var body: some View { HStack { Button("END") { isFocused = false } TextField("Task", text: $task.title) .focused($isFocused) } // 视图出现时同步外部焦点指令 .onAppear { isFocused = shouldFocus } // 外部焦点状态变化时更新内部焦点 .onChange(of: shouldFocus) { newShouldFocus in isFocused = newShouldFocus } } }
方案2:双向同步焦点状态
需要子视图焦点变化同步回父视图的场景:
父视图Cell配置代码:
@State private var focusedTask: Task? cell.configurationUpdateHandler = { [self] (cell, state) in // 创建双向绑定关联父视图状态 let shouldFocusBinding = Binding( get: { focusedTask == task }, set: { isFocused in focusedTask = isFocused ? task : nil } ) cell.contentConfiguration = UIHostingConfiguration { TaskView(task: task, shouldFocus: shouldFocusBinding) } }
修改后的TaskView:
struct TaskView: View { @ObservedObject var task: Task @Binding var shouldFocus: Bool @FocusState private var isFocused: Bool var body: some View { HStack { Button("END") { isFocused = false } TextField("Task", text: $task.title) .focused($isFocused) } .onAppear { isFocused = shouldFocus } // 内部焦点变化同步回父视图 .onChange(of: isFocused) { newIsFocused in shouldFocus = newIsFocused } // 父视图状态变化同步到内部焦点 .onChange(of: shouldFocus) { newShouldFocus in isFocused = newShouldFocus } } }
关键修改点
- 移除
TaskView初始化方法中对@FocusState的wrappedValue赋值操作。 - 使用
@FocusState私有变量管理内部焦点,通过onAppear和onChange实现与外部状态的同步。 - 如需双向同步,通过
Binding将子视图焦点状态与父视图状态关联,避免状态割裂。
内容的提问来源于stack exchange,提问作者Nikodem
相关产品推荐
相关产品推荐

