Struct SwiftUI-在ForEach中更改结构数据集?

Struct SwiftUI-在ForEach中更改结构数据集?,struct,foreach,swiftui,Struct,Foreach,Swiftui,我是编程和SwiftUI新手,我正在制作这个应用程序,用户可以选择这些标有A-D的按钮。他们可以选择多个按钮,我希望当他们单击按钮时,背景颜色将从灰色变为绿色。但是,如果我将底部代码中的“//Here”替换为 Data.Selected = true Data.Colour = .green 我得到一个错误,说“无法分配给属性:'Data'是'let'常量”。我理解这意味着什么,但我不知道如何将数据更改为var。我尝试在“Data in”前面键入var,但我得到的错误是“一行中的连续语句必须用

我是编程和SwiftUI新手,我正在制作这个应用程序,用户可以选择这些标有A-D的按钮。他们可以选择多个按钮,我希望当他们单击按钮时,背景颜色将从灰色变为绿色。但是,如果我将底部代码中的“//Here”替换为

Data.Selected = true
Data.Colour = .green
我得到一个错误,说“无法分配给属性:'Data'是'let'常量”。我理解这意味着什么,但我不知道如何将数据更改为var。我尝试在“Data in”前面键入var,但我得到的错误是“一行中的连续语句必须用“;”分隔”。我是否可以直接修改数据/按钮数据?还是有解决办法

struct Buttons: Hashable {
    var Crit: String
    var Selected: Bool
    var Colour: Color
}

var ButtonsData = [
    Buttons(Crit: "A", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "B", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "C", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "D", Selected: false, Colour: Color(.systemGray4))
]

struct CritView: View {
    
    @Binding var CritBoard: Bool
    @Binding var BackgroundColor: Color
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            
            ScrollView(.vertical, showsIndicators: false) {
                HStack(spacing: 15) {
                    ForEach(ButtonsData, id: \.self) { Data in
                        Button(action: {
                          // HERE
                        }) {
                            Text(Data.Crit)
                                .font(.system(size: 30))
                        }
                        .frame(width: 65, height: 55)
                        .background(Data.Colour)
                        .cornerRadius(10)
                    }
                }
                .padding(.top, 50)
            }
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height/8)
            .padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom)
            .background(Color(.white))
            .cornerRadius(25)
            
            Button(action: {
                self.CritBoard.toggle()
                self.BackgroundColor = .white
            }) {
                Image(systemName: "xmark").foregroundColor(.black)
            }.padding(25)
        }
    }
}

以下是可能的解决方案-创建索引/值元组数组,并按索引修改原始容器中的数据:

ForEach(Array(ButtonsData.enumerated()), id: \.element) { i, Data in
    Button(action: {
      ButtonsData[i].Selected = true
      ButtonsData[i].Colour = .green
    }) {
        Text(Data.Crit)
            .font(.system(size: 30))
    }
    .frame(width: 65, height: 55)
    .background(Data.Colour)
    .cornerRadius(10)
}

嗯,我不认为很多人会有相同/类似的问题,但这是我的工作代码。该代码使用了@Aspersi的答案以及Swift文章中的代码。(这可能不是最简单的代码,但至少现在可以使用)

完整代码如下

struct Buttons: Hashable {
    var Crit: String
    var Selected: Bool = false
    var Colour: Color
}

var ButtonsData = [
    Buttons(Crit: "A", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "B", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "C", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "D", Selected: false, Colour: Color(.systemGray4))
]

struct CritView: View {
    
    @Binding var CritBoard: Bool
    @Binding var BackgroundColor: Color
    
    @State private var AllData = ButtonsData
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            
            ScrollView(.vertical, showsIndicators: false) {
                HStack(spacing: 15) {
                    ForEach(Array(ButtonsData.enumerated()), id: \.element) { I, Data in
                        Button(action: {
                            self.AllData[i].Selected.toggle()
                            if self.AllData[i].Selected == true {
                                self.AllData[i].Colour = .green
                            } else {
                                self.AllData[i].Colour = Color(.systemGray4)
                            }
                        }) {
                            Text(Data.Crit)
                                .font(.system(size: 30))
                        }
                        .frame(width: 65, height: 55)
                        .background(self.AllData[i].Colour)
                        .cornerRadius(10)
                    }
                }
                .padding(.top, 50)
            }
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height/8)
            .padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom)
            .background(Color(.white))
            .cornerRadius(25)
            
            Button(action: {
                self.CritBoard.toggle()
                self.BackgroundColor = .white
            }) {
                Image(systemName: "xmark").foregroundColor(.black)
            }.padding(25)
        }
    }
}

谢谢你的回答!在复制和粘贴代码后,没有出现任何错误,但不幸的是没有工作。问题是,虽然“ButtonsData[i].color”确实已更改,“.background(ButtonsData[i].color)”没有更改,因为它不是@State变量。我做了一些搜索,发现这篇使用Swift文章的黑客攻击很有帮助()。因此,我添加了“@State private var AllData=ButtonsData”,并将“ButtonsData[I].color”更改为“self.AllData[I].color”。
struct Buttons: Hashable {
    var Crit: String
    var Selected: Bool = false
    var Colour: Color
}

var ButtonsData = [
    Buttons(Crit: "A", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "B", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "C", Selected: false, Colour: Color(.systemGray4)),
    Buttons(Crit: "D", Selected: false, Colour: Color(.systemGray4))
]

struct CritView: View {
    
    @Binding var CritBoard: Bool
    @Binding var BackgroundColor: Color
    
    @State private var AllData = ButtonsData
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            
            ScrollView(.vertical, showsIndicators: false) {
                HStack(spacing: 15) {
                    ForEach(Array(ButtonsData.enumerated()), id: \.element) { I, Data in
                        Button(action: {
                            self.AllData[i].Selected.toggle()
                            if self.AllData[i].Selected == true {
                                self.AllData[i].Colour = .green
                            } else {
                                self.AllData[i].Colour = Color(.systemGray4)
                            }
                        }) {
                            Text(Data.Crit)
                                .font(.system(size: 30))
                        }
                        .frame(width: 65, height: 55)
                        .background(self.AllData[i].Colour)
                        .cornerRadius(10)
                    }
                }
                .padding(.top, 50)
            }
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height/8)
            .padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom)
            .background(Color(.white))
            .cornerRadius(25)
            
            Button(action: {
                self.CritBoard.toggle()
                self.BackgroundColor = .white
            }) {
                Image(systemName: "xmark").foregroundColor(.black)
            }.padding(25)
        }
    }
}