I am attempting to have a list that when a cell it tapped it changes the hasBeenSeen Bool value within the State object itself.
struct State: Identifiable {
var id = UUID()
let name: String
var hasBeenSeen: Bool = false
}
struct ContentView: View {
let states: [State] = [
State(name: "Oregon", hasBeenSeen: true),
State(name: "California", hasBeenSeen: true),
State(name: "Massachussets", hasBeenSeen: false),
State(name: "Washington", hasBeenSeen: true),
State(name: "Georgia", hasBeenSeen: false)
]
var body: some View {
NavigationView {
List {
ForEach(states, id: \.id) { state in
StateCell(state: state)
}
}.navigationBarTitle(Text("States"))
}
}
}
struct StateCell: View {
var state: State
var body: some View {
HStack {
Text(state.name)
Spacer()
if state.hasBeenSeen {
Image(systemName: "eye.fill")
}
}.onTapGesture {
// state.hasBeenSeen.toggle()
}
}
}
My original thought is that I need to make hasBeenSeen to a @State var but that doesn't seem to work. How can I make this Bool val editable from a list?
Views in SwiftUI are immutable - they are just structures - so you can't change their properties. That's why SwiftUI has a concept of a
@Stateproperty wrapper. When you change "state" property, SwiftUI actually updates the state value, not the view's property value (which is, again, immutable).So, you need to set
@Stateon thestatesproperty within your view. (You'd also need to change the name, since identifierStateis already taken by theStateproperty wrapper - so I just changed it toStateEntity)That's not enough, though, since when you pass an element of the
statesarray (aStateEntityvalue) to a child view, you're just passing a copy.For that, you'd need a binding. A binding allows child views to modify state properties of parent views, without owning the data. So, the child view's property should use the
@Bindingproperty wrapper:SwiftUI made it easy to get the binding of state property by using the projected value, which in this case is
$states.However, you need to pass a binding not to the entire array, but to a specific element of that array. That, unfortunately (and rather annoyingly), is a bit trickier. You need to get the index of the element, and given the index, access the binding like so:
$state[index].One way is to do a
ForEachover indices ofstates: