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

iOS 16 UIHostingConfiguration中@FocusState无法更新.wrappedValue问题

解决UIHostingConfiguration中@FocusState无法更新焦点的问题

问题根源

  1. @FocusState初始化赋值无效:SwiftUI的@FocusState绑定需在视图进入渲染上下文后才生效,直接在init中设置wrappedValue不会起作用。
  2. 视图实例重复创建:UIHostingConfiguration每次更新cell配置时,都会重新实例化TaskView,导致内部@FocusState状态被重置为初始值。
  3. 单向状态传递缺陷:仅通过参数单向传递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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 07:54:22