I made a grid using LazyGrid and I want to change individual item background color when it tapped based on its current selection status in the data model.
I tried to use onTapGesture() it doesn't reload the grid and update the background color
class Day: Identifiable {
let id = UUID()
let value: Int
var isSelected: Bool
init(value: Int, isSelected: Bool) {
self.value = value
self.isSelected = isSelected
}
}
import SwiftUI
struct ContentView: View {
var days = [
Day(value: 1, isSelected: true),
Day(value: 2, isSelected: false),
Day(value: 3, isSelected: false),
Day(value: 4, isSelected: true)
]
let layout = [
GridItem(.fixed(40)),
GridItem(.fixed(40)),
GridItem(.fixed(40)),
GridItem(.fixed(40))
]
var body: some View {
ScrollView {
LazyVGrid(columns: layout) {
ForEach(days) { day in
Capsule()
.overlay(Text("\(day.value)").foregroundColor(.white))
.foregroundColor(day.isSelected ? .blue : .red)
.frame(height: 40)
.onTapGesture {
days[0].isSelected.toggle()
}
}
}
}
}
}
Try this approach, as mentioned using a struct Day
and enumerated
in the ForEach
loop, and @State private var days ...
as shown in the example code:
struct Day: Identifiable { // <--- here
let id = UUID()
let value: Int
var isSelected: Bool
init(value: Int, isSelected: Bool) {
self.value = value
self.isSelected = isSelected
}
}
struct ContentView: View {
@State private var days = [ // <--- here
Day(value: 1, isSelected: true),
Day(value: 2, isSelected: false),
Day(value: 3, isSelected: false),
Day(value: 4, isSelected: true)
]
let layout = [
GridItem(.fixed(40)),
GridItem(.fixed(40)),
GridItem(.fixed(40)),
GridItem(.fixed(40))
]
var body: some View {
ScrollView {
LazyVGrid(columns: layout) {
// --- here
ForEach(Array(days.enumerated()), id: \.offset) { index, day in
Capsule()
.overlay(Text("\(day.value)").foregroundColor(.white))
.foregroundColor(day.isSelected ? .blue : .red)
.frame(height: 40)
.onTapGesture {
days[index].isSelected.toggle() // <--- here
}
}
}
}
}
}
Or:
struct ContentView: View {
@State private var days = [
Day(value: 1, isSelected: true),
Day(value: 2, isSelected: false),
Day(value: 3, isSelected: false),
Day(value: 4, isSelected: true)
]
let layout = [
GridItem(.fixed(40)),
GridItem(.fixed(40)),
GridItem(.fixed(40)),
GridItem(.fixed(40))
]
var body: some View {
ScrollView {
LazyVGrid(columns: layout) {
ForEach(days) { day in
Capsule()
.overlay(Text("\(day.value)").foregroundColor(.white))
.foregroundColor(day.isSelected ? .blue : .red)
.frame(height: 40)
.onTapGesture {
if let index = days.firstIndex(where: {$0.id == day.id}) {
days[index].isSelected.toggle() // <--- here
}
}
}
}
}
}
}