SwiftUI中上下文菜单未更新

12

我正在尝试使用SwiftUI的.contextMenu设置一个按钮来切换Bool值。当Bool切换时,上下文菜单的按钮文本应该更改。但是上下文菜单没有更新。有没有一种方法可以强制更新上下文菜单?

以下是描述问题的示例代码:

import SwiftUI

struct Item: Identifiable {
    let id = UUID()
    let user: String
    var active: Bool
}

struct ContentView: View {
    @State var items: [Item] = [
        Item(user: "Daniel",active: false),
        Item(user: "Jack", active: true),
        Item(user: "John", active: true)
    ]
    
    @State var isOn : Bool = false
    var body: some View {
        List {
            ForEach(items) { item in
                VStack {
                    Text("\(item.user)")
                        
                    HStack {
                        Text("Active ? ")
                        Text(item.active ? "YES": "NO")
                    }
                }.contextMenu{
                    Button(action: {
                        let index = items.firstIndex{$0.user == item.user}
                        
                        items[index!].active.toggle()
                    }) {
                        Text(item.active ? "Set as Active": "Set as Inactive")
                    }
                }
            }
        }
    }
}
2个回答

11

这是SwiftUI中的一个bug,在Xcode 13.2 beta 2的模拟器中仍然存在问题。

我设法通过在if item.active语句的两个分支中都复制列表项来解决这个问题,像这样:

struct ContentView: View {
    @State var items: [Item] = [
        Item(user: "Daniel",active: false),
        Item(user: "Jack", active: true),
        Item(user: "John", active: true)
    ]

    var body: some View {
        List {
            ForEach(items) { item in
                // work around SwiftUI bug where
                // context menu doesn't update
                if item.active { listItem(for: item) }
                else { listItem(for: item) }
            }
        }
    }

    private func listItem(for item: Item) -> some View {
        VStack {
            Text("\(item.user)")

            HStack {
                Text("Active ? ")
                Text(item.active ? "YES": "NO")
            }
        }
        .contextMenu {
            Button(item.active ? "Deactivate" : "Activate") {
                if let index = items.firstIndex(where: { $0.id == item.id }) {
                    items[index].active.toggle()
                }
            }
        }
        .id(item.id)
    }
}

在 Xcode 13.4(13F17a)上,无论是模拟器还是实机,问题仍然存在。 - nishanthshanmugham

4

这是SwiftUI在iOS 15中的一个bug。iOS 14和16会在状态变量更改时正常更新。

可以通过将ContextMenu添加到项的后台(在此示例中为Color.clear)来解决此问题。这还需要将id设置为已更改的属性(在此示例中为item.active)。

struct Item: Identifiable {
    let id = UUID()
    let user: String
    var active: Bool
}

struct ContentView: View {
    @State var items: [Item] = [
        Item(user: "Daniel", active: false),
        Item(user: "Jack", active: true),
        Item(user: "John", active: true)
    ]

    var body: some View {
        List {
            ForEach(items) { item in
                VStack {
                    Text("\(item.user)")
                        
                    HStack {
                        Text("Active ? ")
                        Text(item.active ? "YES": "NO")
                    }
                }
                .background {
                    Color.clear
                        .contextMenu{
                            Button(action: {
                                if let index = items.firstIndex(where: {$0.user == item.user}) {
                                    items[index].active.toggle()
                                }
                            }) {
                                Text(item.active ? "Set as Inactive": "Set as Active")
                            }
                        }
                        .id(item.active)
                }
            }
        }
    }
}

1
谢谢!这是一个奇怪的问题。 - Alex Hartford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接