【问题标题】:SwiftUI: onDelete doesn't update UI correctlySwiftUI:onDelete 无法正确更新 UI
【发布时间】:2020-10-07 10:17:41
【问题描述】:

当我使用onDelete() 删除数组的元素时,它会删除数据中的正确项,但会删除 UI 上的最后一项。我看到了this answer,但我已经在使用它推荐的东西了。有什么建议吗?

struct ContentView: View {
    @State var items = ["One", "Two", "Three"]
    
    var body: some View {
        Form{
            ForEach(items.indices, id:\.self){ itemIndex in
                
                let item = self.items[itemIndex]
                
                EditorView(container: self.$items, index: itemIndex, text: item)
                
            }.onDelete(perform: { indexSet in

                self.items.remove(atOffsets: indexSet)

            })
        }
    }
}

这是 EditorView 结构:

struct EditorView : View {
    var container: Binding<[String]>
    var index: Int

    @State var text: String
    
    var body: some View {
        TextField("Type response here", text: self.$text, onCommit: {
            self.container.wrappedValue[self.index] = self.text
            
        })
    }
}

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    您的ForEach 正在循环您的数组的indices,因此SwiftUI 就是用来识别它们的。当您删除一项时,数组的索引会减少一个,因此 SwiftUI 将其解释为最后一个已被删除。

    要正确执行此操作,您应该循环遍历具有唯一 idIdentifiable 项目列表。在这里,我创建了一个名为MyItemstruct,它包含原始String 和一个唯一生成的id。我使用.map(MyItem.init) 将项目转换为[MyItem]

    此外,您的代码需要循环中的索引,因此循环遍历Array(items.enumerated()),这将为您提供(offset, element) 元组的数组。然后告诉 SwiftUI 使用\.element.id 作为id

    请注意,EditorView 现在采用 MyItem 数组。

    通过这些更改,SwiftUI 将能够识别您从列表中删除的项目并正确更新 UI。

    struct MyItem: Identifiable {
        var name: String
        let id = UUID()
    }
    
    struct ContentView: View {
        @State var items = ["One", "Two", "Three"].map(MyItem.init)
        
        var body: some View {
            Form{
                ForEach(Array(items.enumerated()), id: \.element.id) { index, item in
                    
                    EditorView(container: self.$items, index: index, text: item.name)
                    
                }.onDelete(perform: { indexSet in
                    
                    self.items.remove(atOffsets: indexSet)
                })
            }
        }
    }
    
    struct EditorView : View {
        var container: Binding<[MyItem]>
        var index: Int
        
        @State var text: String
        
        var body: some View {
            TextField("Type response here", text: self.$text, onCommit: {
                self.container.wrappedValue[self.index].name = self.text
            })
        }
    }
    

    【讨论】:

    • 谢谢,这解决了问题。此外,如果您对了解 Identifiable 的资源有任何建议,我们将不胜感激。
    • 正如您将在教程中看到的那样,Identifiable 工作得很好,因为您可以只遍历列表,但在您的情况下,您还需要索引,所以我们并没有真正使用 @在这种情况下使用 987654341@ 协议,因为我们在 ForEach 中明确指定了 id。
    • 感谢您的回答和建议。我花了几个小时尝试使用 Identifiable 尝试不同的东西,并认为我已经掌握了它。
    猜你喜欢
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 2023-01-05
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多