list - 多个视图上的 SwiftUI 状态
问题描述
在 SwiftUI 中,首先处理应用程序的状态似乎非常简单。本质上有两个属性包装器:@EnvironmentObject
和@ObservedObject
(和@State
)。但事实证明,事情并没有那么简单。
我在这里发布了几个问题。他们中的大多数都得到了很好的回答: SwiftUI onDelete List with Toggle,SwiftUI ForEach with .indices() does not update after onDelete,SwiftUI: Index out of range when delete cells with toggle
但每次我走得更远,一些主要问题仍然存在。这些是
NavigationLink
通过aList
或 a将可绑定变量移交ForEach
给 SubView,并将更改反映回 MainView。(我尝试了几种解决方案,例如.indices
在数组上使用并动态绑定(SwiftUI onDelete List with Toggle))。为了反映变化,我还尝试使用.onReceive()
也不起作用的。- 当我尝试使用这个公式时,我总是遇到索引问题:
someArray.firstIndex(where {condition})!
. 你可以在 Apple 的 SwiftUI 教程中找到它。当我在ForEach
-closure 中使用索引然后尝试使用.onDelete()
. 错误信息是:
Thread 1: Fatal error: Index out of range
- 如何将变量绑定到
@EnvironmentObject
主视图后面两层或多层的模型?使用 2. 中的公式会产生非常长的变量名。这似乎不对。
这是一个例子,它几乎可以工作。唯一不起作用的是MainView
当我更改SubViews
. 但是在我的应用程序中使用几个对我来说并不合适ObservedObjects
。
class Model: ObservableObject {
@Published var items: [Item]
init(name: String, items: [Item]) {
self.items = items
}
}
class Item: Identifiable, ObservableObject {
var id = UUID()
var itemName: String
@Published var subItems: [SubItem]
init(itemName: String, payments: [SubItem]) {
self.itemName = itemName
self.subItems = payments
}
}
class SubItem: Identifiable, ObservableObject {
var id = UUID()
var isOn: Bool
init(isOn: Bool) {
self.isOn = isOn
}
}
struct MainView: View {
@EnvironmentObject var model: Model
var body: some View {
NavigationView {
List {
ForEach(model.items) {item in
NavigationLink(destination: SubView1(item: item)) {
HStack{
Text(item.itemName)
Text(item.subItems[0].isOn ? "True":"False") // I know: bad, but only for quick debugging reasons
Text(item.subItems[1].isOn ? "True":"False")
}
}.onReceive(item.objectWillChange, perform: {self.model.objectWillChange.send()})
}.onDelete(perform: delete)
}
}
}
func delete(at offsets: IndexSet) {
self.model.items.remove(atOffsets: offsets)
}
}
struct SubView1: View {
@ObservedObject var item: Item
var body: some View {
List {
ForEach(item.subItems) {subItem in
NavigationLink(destination: SubView2(subItem: subItem)) {
ToggleView(subItem: subItem)
}
}.onDelete(perform: delete)
}
}
func delete(at offsets: IndexSet) {
self.item.subItems.remove(atOffsets: offsets)
}
}
struct SubView2: View {
@ObservedObject var subItem: SubItem
var body: some View {
Toggle(isOn: $subItem.isOn) {
Text("Toggle-Text")
}
}
}
struct ToggleView: View {
@ObservedObject var subItem: SubItem
var body: some View {
Toggle(isOn: $subItem.isOn) {
Text("Toggle-Text")
}
}
}
解决方案
您可以做的是访问项目的绑定并在以下位置使用它ToggleView
:
struct SubView1: View {
@ObservedObject var item: Item
var body: some View {
List {
ForEach(0..<item.subItems.count, id: \.self) { index in
NavigationLink(destination: SubView2(subItem: self.$item.subItems[index])) { // <- pass the binding
ToggleView(subItem: self.$item.subItems[index]) // <- pass the binding
}
}.onDelete(perform: delete)
}
}
...
}
struct SubView2: View {
@Binding var subItem: SubItem // <- receive the binding
var body: some View {
Toggle(isOn: $subItem.isOn) {
Text("Toggle-Text")
}
}
}
struct ToggleView: View {
@Binding var subItem: SubItem // <- receive the binding
var body: some View {
Toggle(isOn: $subItem.isOn) {
Text("Toggle-Text")
}
}
}
推荐阅读
- r - 如何根据我在 R 中的数据框的某些条件创建有向邻接矩阵?
- javascript - 将 257.78 乘以 100 的正确方法 - 浮点精度错误
- mysql - MYSQL 从 Table1 获取 id 并在 INSERTING 值时插入到 Table2(用户表单)
- unity3d - 在 Unity 中围绕瓷砖平台移动对象
- ios - 如何以编程方式将数据从表视图控制器传递到另一个控制器?
- python - 从多个字典列表中返回特定键中具有最高值的字典
- c# - .NET 无法使用 sinch 发送 SMS
- image-processing - 将图像的像素更改为给定颜色集中最接近的颜色
- pandas - Pandas 获得预聚合数据的中值/平均值
- python - Python 中的 pre_word() 函数