提问者:小点点

完整列表将重新创建所有视图,即使只更改了一项


我有一个非常简单的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次。 我的理解是它应该只做一次?


共1个答案

匿名用户

下面是一个例子,说明它是如何工作的。 已测试并在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")
            }
        }
    }
    
}