我有一个非常简单的SwiftUI列表视图示例,它从数组中的数据呈现项。 数组中的数据是可识别的。 但是,当我更改数组中的数据时,添加或删除一个项,然后重新创建列表视图中的所有行。 那是正确的吗? 我的理解是,Identiable应该确保只重新创建列表中被更改的视图。
我的列表在一个导航视图中,每一行都链接到一个详细信息视图。 问题是,由于列表中的所有项目都在每次数据更改时被删除并重新创建,因此如果在详细信息视图中发生了这种情况(由通知触发),那么Im就会被抛回到列表中。
我错过了什么?
编辑:添加的代码示例
这是我的数据结构:
struct Item: Identifiable {
let id: UUID
let name: String
init(name: String) {
self.id = UUID()
self.name = name
}
}
这是我的项目视图
struct ItemView: View {
var item: Item
init(item: Item) {
self.item = item
print("ItemView created \(self.item.id)")
}
var body: some View {
Text(self.item.name)
}
}
最终我的列表视图:
struct KeyList: View {
@State var items = [Item(name: "123"), Item(name: "456"), Item(name: "789")]
var body: some View {
VStack {
List(self.items) { item in
ItemView(item: item)
}
Button(action: {
self.items.append(Item(name: "New"))
}) {
Text("Add")
}
}
}
}
当我按下添加时,它将打印“ItemView Created”4次。 我的理解是它应该只做一次?
下面是一个例子,说明它是如何工作的。 已测试并在iOS 13.5上运行
当只删除一个项目时,不会重新创建列表。 这样就完成了。
关于视图的弹出,这里已经回答了:SwiftUI ForEach refresh使视图弹出
我这里有一个解决这个问题的小方法。 将要移除的项添加到数组中。 然后在返回时,删除这些项(这将使视图弹出),或者以编程方式返回,并不删除任何内容
struct ContentView: View {
@State var text:Array<String> = ["a", "b", "c"]
var body: some View {
NavigationView() {
VStack() {
List() {
ForEach(self.text, id: \.self){ item in
NavigationLink(destination: SecondView(textItem: item, text: self.$text)) {
Text(item)
}
}
}
Button(action: {
self.text.remove(at: 0)
}){
Text("Remove \(self.text[0])")
}
}
}
}
}
struct SecondView: View {
@State var textItem: String
@Binding var text: Array<String>
@State var tmpArray: Array<String> = []
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
VStack() {
Text(self.textItem)
Button(action: {
//Append to a tmp array which will later be used to determine what to remove
self.tmpArray.append(self.text[0])
}){
Text("Remove \(self.text[0])")
}
Button(action: {
if self.tmpArray.count > 0 {
//remove your stuff which will automatically pop the view
self.text.remove(at: 0)
} else {
// programmatically go back as nothing has been deleted
self.presentationMode.wrappedValue.dismiss()
}
}){
Text("Go Back")
}
}
}
}