SwiftUI中List内TextField输入时停止更新无法连续编辑如何解决?
问题解决方法
根因分析
- 你的
Fruit结构体每次调用updateName生成新实例时,都会生成全新的UUID作为唯一标识,List的ForEach会将其识别为完全不同的新元素,直接销毁旧行视图、创建新行视图,自然丢失当前编辑焦点和输入状态。 - 你未指定ForEach的元素匹配规则,SwiftUI默认按值类型整体哈希判断是否重绘,即使id不变也可能出现不必要的重绘。
修复步骤
1. 修改Fruit结构,更新时复用原有ID
保证修改name前后的实例ID完全一致,ForEach才会判定为同一行,不会销毁重建:
struct Fruit: Identifiable { let id: UUID let name: String // 初始化新实例时生成唯一ID init(name: String) { self.id = UUID() self.name = name } // 更新name时复用原有ID func updateName(newName: String) -> Fruit { return Fruit(id: self.id, name: newName) } }
2. 明确ForEach的元素匹配规则
修改ListView中的ForEach写法,指定按id匹配元素,减少不必要的重绘:
struct ListView: View { @StateObject var viewModel = ViewModel() var body: some View { List { ForEach(viewModel.fruits, id: \.id) { fruit in ListViewRow(fruit: fruit) } } .environmentObject(viewModel) } }
3. 可选优化:降低数据源更新频率
如果不需要输入内容实时同步到ViewModel,可以将同步逻辑从onChange移到编辑结束的回调中,进一步减少重绘次数:
struct ListViewRow: View { @EnvironmentObject var viewModel: ViewModel @State var fruitTextField: String let fruit: Fruit init(fruit: Fruit) { self.fruit = fruit _fruitTextField = State(initialValue: fruit.name) } var body: some View { TextField("", text: $fruitTextField) // 按回车结束编辑时同步 .onSubmit { viewModel.updateName(newName: fruitTextField, fruit: fruit) } // 行消失时同步,避免滑走未保存 .onDisappear { viewModel.updateName(newName: fruitTextField, fruit: fruit) } } }
修改完成后即可正常连续输入,不会出现编辑状态丢失的问题。
内容的提问来源于stack exchange,提问作者Vladislav Bogucharov
相关产品推荐
相关产品推荐

