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

SwiftUI如何修复数组内TextField每输入一个字符就失焦的问题

问题根因

这个问题和Observable Object无关,完全是列表元素标识不稳定导致的重绘问题,具体问题点有两个:

  • 你定义的CmdOption结构体的id是计算属性,每次访问都会生成全新的UUID,无法作为元素的唯一稳定标识。
  • ForEach使用\.self作为元素的唯一标识,当你修改TextField绑定的value字段时,值类型的CmdOption实例的哈希值会发生变化,SwiftUI会判定原有元素被删除、新元素被插入,直接重建对应位置的TextField,导致输入框失去第一响应者状态(失焦)。
修复方案

只需修改两处即可解决问题:

  1. 将CmdOption的id改为存储属性,初始化时生成一次即固定,保证元素标识不会随内容变化
  2. 移除ForEach的id: \.self参数,直接使用Identifiable协议自带的稳定id作为列表元素标识
修复后完整可运行代码
struct CmdOption: Hashable, Identifiable {
    // id改为存储属性,初始化时生成一次固定不变
    let id = UUID()
    var value: String
}

import SwiftUI

struct ContentView: View {
    
    @State var theOptions: [CmdOption] = [
        CmdOption(value: ""),
        CmdOption(value: "")
    ]
    
    @State var allOptions: [CmdOption] = []
    
    var body: some View {
        VStack {
            ScrollView(.vertical) {
                // 移除id: \.self,直接用Identifiable的稳定id
                ForEach($allOptions)  { $option in
                    VStack {
                        TextField(option.value, text: $option.value)
                    }
                }
            }
        }.onAppear {
            startup()
        }
    }
    func startup() {
        allOptions.removeAll()
        theOptions.forEach {option in
            allOptions.append(option)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 16:36:03