为什么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()
    }
}