为什么List中的TextField停止更新?
Why does the TextField in the List stop updating?
我开始研究 SwiftUI,想做一个标准提醒的原型,就像在 iPhone 中一样。看起来没什么复杂的,有一个List,每个cell一个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: { [=10=].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()
}
}
您可以通过以下方式进一步简化它:
struct Fruit: Identifiable {
let id = UUID()
var name: String
}
class ViewModel: ObservableObject {
@Published var fruits: [Fruit] = [Fruit(name: "apple"), Fruit(name: "banana"), Fruit(name: "orange")]
}
struct ListView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
List {
ForEach($viewModel.fruits) { $fruit in
ListViewRow(fruit: $fruit)
}
}
}
}
struct ListViewRow: View {
@Binding var fruit: Fruit
var body: some View {
TextField("", text: $fruit.name)
}
}
话虽如此,您确实需要查看评论中链接的 Apple Swift 教程。
编辑:Lorem Ipsum 的完整项目代码:
//
// ContentView.swift
// FruitApp
//
// Created by Developer on 11/27/21.
//
import SwiftUI
struct Fruit: Identifiable {
let id = UUID()
var name: String
}
class ViewModel: ObservableObject {
@Published var fruits: [Fruit] = [Fruit(name: "apple"), Fruit(name: "banana"), Fruit(name: "orange")]
}
struct ListView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
List {
ForEach($viewModel.fruits) { $fruit in
ListViewRow(fruit: $fruit)
}
}
}
}
struct ListViewRow: View {
@Binding var fruit: Fruit
var body: some View {
TextField("", text: $fruit.name)
}
}
struct ContentView: View {
var body: some View {
ListView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我开始研究 SwiftUI,想做一个标准提醒的原型,就像在 iPhone 中一样。看起来没什么复杂的,有一个List,每个cell一个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: { [=10=].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()
}
}
您可以通过以下方式进一步简化它:
struct Fruit: Identifiable {
let id = UUID()
var name: String
}
class ViewModel: ObservableObject {
@Published var fruits: [Fruit] = [Fruit(name: "apple"), Fruit(name: "banana"), Fruit(name: "orange")]
}
struct ListView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
List {
ForEach($viewModel.fruits) { $fruit in
ListViewRow(fruit: $fruit)
}
}
}
}
struct ListViewRow: View {
@Binding var fruit: Fruit
var body: some View {
TextField("", text: $fruit.name)
}
}
话虽如此,您确实需要查看评论中链接的 Apple Swift 教程。
编辑:Lorem Ipsum 的完整项目代码:
//
// ContentView.swift
// FruitApp
//
// Created by Developer on 11/27/21.
//
import SwiftUI
struct Fruit: Identifiable {
let id = UUID()
var name: String
}
class ViewModel: ObservableObject {
@Published var fruits: [Fruit] = [Fruit(name: "apple"), Fruit(name: "banana"), Fruit(name: "orange")]
}
struct ListView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
List {
ForEach($viewModel.fruits) { $fruit in
ListViewRow(fruit: $fruit)
}
}
}
}
struct ListViewRow: View {
@Binding var fruit: Fruit
var body: some View {
TextField("", text: $fruit.name)
}
}
struct ContentView: View {
var body: some View {
ListView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}