为什么即使列表已正确更新,上下文菜单仍显示旧状态?

Why does Context Menu display the old state even though the List has correctly been updated?

我遇到了一个问题,即显示的 Context Menu 显示了错误的数据,尽管下面的 List 显示了正确的数据。问题是,一旦触发第一项的上下文菜单上的操作,您将看到 List 如何重新呈现并显示正确的数据,但是如果您再次为第一项触发上下文菜单,它不会显示正确的状态。如果你打开第二个项目的上下文菜单,它会显示正确的状态,但如果你现在 select “Two”,并打开相同的上下文菜单,State 将是错误的(它'当它应该显示 1 和 2 时,我将只显示 1 selected,就像 List 显示它一样)。

感觉差了一个(比如显示以前的状态而不是最新的状态)我不确定这只是一个错误还是我用错了。

这是重现问题的代码片段:

@main
struct ContextMenuBugApp: App {
    
    let availableItems = ["One", "Two", "Three", "Four", "Five"]
    @State var selectedItems: [String] = []
    
    var body: some Scene {
        WindowGroup {
            List {
                ForEach(availableItems, id: \.self) { item in
                    HStack {
                        let isAlreadySelected = selectedItems.contains(item)
                        Text("Row \(item), selected: \(isAlreadySelected ? "true" : "false")")
                    }.contextMenu {
                        ForEach(availableItems, id: \.self) { item in
                            let isAlreadySelected = selectedItems.contains(item)
                            Button {
                                isAlreadySelected ? selectedItems.removeAll(where: { [=10=] == item }) : selectedItems.append(item)
                            } label: {
                                Label(item, systemImage: isAlreadySelected ? "checkmark.circle.fill" : "")
                            }
                        }
                    }
                }
            }
        }
    }
}

演示该问题的视频:https://twitter.com/xmollv/status/1412397838319898637

谢谢!

编辑:

它似乎是一个 iOS 15 回归(至少在 Release Candidate 上),它在 iOS 14.6.

上运行良好

您可以使用任意 ID 的背景视图强制重绘上下文菜单。即:

@main
struct ContextMenuBugApp: App {
    let availableItems = ["One", "Two", "Three", "Four", "Five"]
    @State var selectedItems: [String] = []
    
    func isAlreadySelected(_ item: String) -> Bool {
        selectedItems.contains(item)
    }
    
    var body: some Scene {
        WindowGroup {
            List {
                ForEach(availableItems, id: \.self) { item in
                    HStack {
                        Text("Row \(item), selected: \(isAlreadySelected(item) ? "true" : "false")")
                    }
                    .background(
                        Color.clear
                            .contextMenu {
                                ForEach(availableItems, id: \.self) { item in
                                    Button {
                                        isAlreadySelected(item) ? selectedItems.removeAll(where: { [=10=] == item }) : selectedItems.append(item)
                                    } label: {
                                        Label(item, systemImage: isAlreadySelected(item) ? "checkmark.circle.fill" : "")
                                    }
                                }
                            }.id(selectedItems.count)
                    )
                }
            }
        }
    }
}

如果不行,你可以试试把id放到没有背景的contextMenu中(这可能是基于iOS的版本,以前不行,所以要小心,先测试一下iOS)