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
}
}
启动应用程序,其颜色和项目名称即为它们读取的内容。
点击“交换项目”按钮后,我希望项目在各节之间交换,但是各节中标签的颜色应保持不变。
实际结果和预期输出在屏幕快照中描述。
这可能是ForEach
中的错误,但是如果我的代码段有问题,我想从社区中获取一个观点。
答案 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])
}
}
}