Полный список воссоздает все представления, даже если был изменен только один элемент - PullRequest
0 голосов
/ 21 июня 2020

У меня есть очень простой школьный пример представления списка SwiftUI, которое отображает элементы из данных в массиве. Данные в массиве идентифицируемы. Но когда я изменяю данные в массиве, добавляю или удаляю элемент, все строки в представлении списка воссоздаются. Это правильно? Насколько я понимаю, Identifiable должен гарантировать, что воссоздается только представление в списке, которое было изменено.

Мой список находится внутри представления навигации, и каждая строка связана с подробным представлением. Проблема в том, что, поскольку все элементы в списке удаляются и воссоздаются каждый раз при изменении данных, то, если это происходит, когда Im в подробном представлении (оно запускается уведомлением), то Im выбрасывается обратно в список.

Что мне не хватает?

Изменить: добавлен пример кода

Это моя структура данных:

struct Item: Identifiable {
    let id: UUID
    let name: String

    init(name: String) {
        self.id = UUID()
        self.name = name
    }
}

Это мой ItemView

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")
            }
        }
    }
}

Когда я нажимаю кнопку добавления, он 4 раза напечатает «ItemView created». Насколько я понимаю, это следует делать только 1 раз?

1 Ответ

0 голосов
/ 21 июня 2020

Вот пример того, как это может работать. Протестировано и работает над iOS 13.5

Список не создается повторно, если удаляется только один элемент. Итак, это было выполнено.

По поводу всплывающего окна View, здесь уже был дан ответ: SwiftUI ForEach refre sh делает вид всплывающим

У меня есть небольшой обходной путь для этой проблемы. Добавьте элементы, которые хотите удалить, в массив. Затем, возвращаясь назад, удалите эти элементы (что сделает вид всплывающим) или go назад программно, и ничего не будет удалено

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")
            }
        }
    }
    
}
...