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

Posted

技术标签:

【中文标题】SwiftUI - 更改 ForEach 中的结构数据集?【英文标题】:SwiftUI - Changing struct data set in ForEach? 【发布时间】:2020-06-23 14:12:39 【问题描述】:

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

Data.Selected = true
Data.Colour = .green

我收到一条错误消息,提示“无法分配给属性:'Data' 是 'let' 常量”。我明白这意味着什么,但我不知道如何将 Data 更改为 var。我尝试在“数据输入”前键入 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)
        
    

【问题讨论】:

【参考方案1】:

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

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)

【讨论】:

感谢您的回答!复制并粘贴您的代码后,没有任何错误,但不幸的是没有工作。问题是,虽然“ButtonsData[i].Colour”确实发生了变化,但“.background(ButtonsData[I].Colour)”却没有,因为它不是@State 变量。我做了一些搜索,发现这篇 Hacking with Swift 文章很有帮助 (hackingwithswift.com/books/ios-swiftui/…)。因此,我添加了“@State private var AllData = ButtonsData”并将“ButtonsData[I].Colour”更改为“self.AllData[i].Colour”。【参考方案2】:

好吧,我不认为很多人实际上会遇到相同/相似的问题,但这是我的工作代码。该代码同时使用了@Aspersi 的答案以及 Hacking with Swift 文章中的代码。 (它可能不是最简化的代码,但至少现在可以工作)

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)

完整代码如下

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)
        
    

【讨论】:

以上是关于SwiftUI - 更改 ForEach 中的结构数据集?的主要内容,如果未能解决你的问题,请参考以下文章

使用 ForEach SwiftUI Core Data 仅更改列表中的一项

在 SwiftUI 中的 forEach 中获取索引和值

SwiftUI:使用 Picker(分段)更改 ForEach 源或获取请求

如何在数组大小更改后刷新 ForEach 显示元素的数量(SwiftUI,Xcode 11 Beta 5)

更改所选按钮颜色 SwiftUI ForEach 数组

SwiftUI:如何使用 ForEach 循环使用各种代码的各种结构?