6

我面临一个问题,即显示Context Menu的数据显示错误,即使List下面显示正确的数据。问题是一旦在第一项的上下文菜单上触发操作,您将看到List重新呈现并显示正确数据的方式,但如果您再次为第一项触发上下文菜单,它将不会显示正确的状态。如果您打开第二个项目的上下文菜单,它将显示正确的状态,但如果您现在选择“Two”,并打开相同的上下文菜单,State则将是错误的(当它应该显示时它只会显示 1 selected 1 & 2,喜欢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: { $0 == item }) : selectedItems.append(item)
                            } label: {
                                Label(item, systemImage: isAlreadySelected ? "checkmark.circle.fill" : "")
                            }
                        }
                    }
                }
            }
        }
    }
}

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

谢谢!

编辑:

这似乎是 iOS 15 的回归(至少在候选版本上),它在 iOS 14.6 上运行良好。

4

1 回答 1

6

您可以强制 contextMenu 使用具有任意 ID 的背景视图重绘。IE:

@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: { $0 == item }) : selectedItems.append(item)
                                    } label: {
                                        Label(item, systemImage: isAlreadySelected(item) ? "checkmark.circle.fill" : "")
                                    }
                                }
                            }.id(selectedItems.count)
                    )
                }
            }
        }
    }
}

如果不行,你可以试试不带背景只把id放到contextMenu(这可能是基于iOS版本的,之前不工作,所以要小心,测试之前的iOS)

于 2021-09-17T09:29:44.240 回答