SwiftUI中的ForEach在Section之间交换视图(从而重新使用它们),而不是更新数据并尊重视图修饰符

时间:2019-11-14 02:09:29

标签: ios foreach swiftui

struct MasterView: View {
    @ObservedObject var store: ModelStore

    var body: some View {
        List {
            Section(header: Text("Black Items")) {
                ForEach(store.bag.blackItems, id: \.self) { item in
                    BlackItemView(model: item)
               }
            }

            Section(header: Text("Blue Items")) {
                ForEach(store.bag.blueItems, id: \.self) { item in
                    BlueItemView(model: item)
                }
            }
        }.navigationBarItems(trailing: Button(action: { self.store.swapItems() }, label: {
            Text("Swap items")
        }))
    }
}

这是swapItems

的实现
func swapItems() {
    var bagCopy = bag
    bagCopy.blackItems = bag.blueItems
    bagCopy.blueItems = bag.blackItems
    self.bag = bagCopy
}
struct Item: Hashable, Identifiable {
   var id: String
}

struct Bag {
    var blackItems: [Item] = [Item(id: "item1")]
    var blueItems: [Item] = [Item(id: "item2")]
}

class ModelStore: ObservableObject {
    var objectWillChange = PassthroughSubject<Void, Never>()
    var bag: Bag = Bag() {
        didSet {
            objectWillChange.send()
        }
    }

    func swapItems() {
        var bagCopy = bag
        bagCopy.blackItems = bag.blueItems
        bagCopy.blueItems = bag.blackItems
        self.bag = bagCopy
    }
}

启动应用程序,其颜色和项目名称即为它们读取的内容。

Initial state

点击“交换项目”按钮后,我希望项目在各节之间交换,但是各节中标签的颜色应保持不变。

实际结果和预期输出在屏幕快照中描述。

enter image description here

这可能是ForEach中的错误,但是如果我的代码段有问题,我想从社区中获取一个观点。

2 个答案:

答案 0 :(得分:0)

我确实向Apple提交了错误报告,但与此同时我找到了解决方法。不是最好的,但它可以工作。解决方案是欺骗ForEach,它们总共有新项目,而不是告诉它们已交换项目。这是ForEach

的更新
List {
        Section(header: Text("Black Items")) {
            ForEach(store.bag.blackItems, id: \.updatedDate) { item in
                BlackItemView(model: item)
           }
        }

        Section(header: Text("Blue Items")) {
            ForEach(store.bag.blueItems, id: \.updatedDate) { item in
                BlueItemView(model: item)
            }
        }
    }

诀窍在于id参数。我将Item更新为具有updatedDate形式的第二个标识符。每次交换项目时,这将具有一个新值。这迫使ForEach放弃其持有的视图并重新创建视图。这是Item结构的变化

struct Item: Hashable, Identifiable {
     var id: String
     var updatedDate: Date = Date()
}

这是ModelStore中swapItems函数的更改

func swapItems() {
    var bagCopy = bag
    bagCopy.blackItems = bag.blueItems.map { item in
        var copy = item
        copy.updatedDate = Date()
        return copy
    }
    bagCopy.blueItems = bag.blackItems.map { item in
        var copy = item
        copy.updatedDate = Date()
        return copy
    }
    self.bag = bagCopy
}

答案 1 :(得分:0)

我找到了您情况的直接答案。您可以使用INDEX,而不是使用值枚举。这样可以保证结果正确。

  List {
Section(header: Text("Black Items")) {
    ForEach(0..<(store.bag.blackItems.count), id: \.self) { index in
        BlackItemView(model: self.store.bag.blackItems[index])
   }
}

Section(header: Text("Blue Items")) {
    ForEach(0..<(store.bag.blueItems.count), id: \.self) { index in
        BlueItemView(model: self.store.bag.blueItems[index])
    }
}
}