Reputation: 345
I am wondering how I can set a state for each generated view (looping through a ForEach).
For example, I would like to loop over this list and have a selection variable for each one (circle is outlined when not selected and filled when selected).
I tried making a local variable, but that doesn't change when a button is pressed because the view is already rendered. I tried adding a "selected variable" to the data model but for some reason it keeps saying I can't change the value because it is a "let constant" even though I created it with a "var".
ForEach(recipe.ingredients, id: \.self) { ingredient in
var selected: Bool = false
Button {
selected = true
print("selected")
} label: {
HStack {
if selected {
Image(systemName: "circle")
.imageScale(.large)
.foregroundColor(Color.pink)
} else {
Image(systemName: "circle.fill")
.imageScale(.large)
.foregroundColor(Color.pink)
}
}
}
}
Here is the model for the data
struct Response: Decodable {
let data: [Data]
}
struct Data: Decodable, Hashable {
let name: String
let image: String
let ingredients: [String]
let instructions: [String]
let servings: String
let time: [String: String]
}
I tried doing the following but it says "selected" is a let constant.
struct Response: Decodable {
let data: [Data]
}
struct Data: Decodable, Hashable {
let name: String
let image: String
var ingredients: [Ingredients]
let instructions: [String]
let servings: String
let time: [String: String]
}
struct Instructions: Decodable, Hashable {
var selected: Bool = false
let instructions: String
}
Upvotes: 0
Views: 43
Reputation: 345
I found a solution. By putting each generated view (from ForEach) into it's own view with it's own state and passing the ingredient down to the other view.
ForEach(recipe.ingredients, id: \.self) { ingredient in
IngredientView(ingredient: ingredient)
}
IngredientView:
struct IngredientView: View {
@State private var selected: Bool = false
var ingredient: String
var body: some View {
Button {
selected.toggle()
} label: {
HStack {
if !selected {
Image(systemName: "circle")
.imageScale(.large)
.foregroundColor(Color.pink)
} else {
Image(systemName: "circle.fill")
.imageScale(.large)
.foregroundColor(Color.pink)
}
}
}
.buttonStyle(.plain)
}
}
Upvotes: 1