【发布时间】:2022-01-05 08:08:00
【问题描述】:
我开始学习 SwiftUI,并想制作一个标准提醒的原型,就像在 iPhone 中一样。看起来没什么复杂的,有一个List,每个单元格都有一个TextField。
但我遇到了一个问题:当我们使用 onChange 更改 TextField 中的文本时,我们会相应地告诉视图模型更新我们的对象。
并且当对象被更新时,整个 List 被重绘并且当前 TextField 的编辑被重置(你不能删除多个字符,也不能添加)。您必须再次单击文本才能继续编辑。
有谁知道如何处理这个问题?
这是我的代码:
import SwiftUI
struct Fruit: Identifiable {
let id = UUID()
let name: String
func updateName(newName: String) -> Fruit {
return Fruit(name: newName)
}
}
class ViewModel: ObservableObject {
@Published var fruits: [Fruit] = [Fruit(name: "apple"), Fruit(name: "banana"), Fruit(name: "orange")]
func updateName(newName: String, fruit: Fruit) {
if let index = fruits.firstIndex(where: { $0.id == fruit.id }) {
fruits[index] = fruit.updateName(newName: newName)
}
}
}
struct ListView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
List {
ForEach(viewModel.fruits) { fruit in
ListViewRow(fruit: fruit)
}
}
.environmentObject(viewModel)
}
}
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)
.onChange(of: fruitTextField) { newValue in
viewModel.updateName(newName: newValue, fruit: fruit)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ListView()
}
}
【问题讨论】:
-
使用绑定而不是状态
-
@loremipsum 我真的不太明白我应该与对方绑定什么,请你解释一下吗?
-
A
@Binding保留对父视图中绑定变量的更新值的引用并传递。 `@State` 只保留它自己的内部值。当您更新父级的@StateObject时,您将创建一个全新的ListViewRow。由于您从未保留输入到 TextField 中的数据,因此它会以您在第一个实例中传递给视图的水果名称重新开始。 -
State 和 StateObject 是事实的来源。绑定是一种双向连接。观看 WWDC21 揭开 SwiftUI 的神秘面纱
标签: swiftui swiftui-list