SwiftUI Edit Struct из списка
Я пытаюсь создать список, который при нажатии на ячейку меняет hasBeenSeen
Bool
значение в State
сам объект.
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()
}
}
}
Моя первоначальная мысль заключается в том, что мне нужно сделать hasBeenSeen
к @State
var, но это, похоже, не работает. Как я могу это сделатьBool
val редактируемый из списка?
1 ответ
Представления в SwiftUI неизменяемы - это просто структуры, поэтому вы не можете изменять их свойства. Вот почему в SwiftUI есть концепция@State
оболочка свойств. Когда вы изменяете свойство "состояние", SwiftUI фактически обновляет значение состояния, а не значение свойства представления (которое, опять же, является неизменным).
Итак, вам нужно установить @State
на states
недвижимость в пределах вашего видения. (Вам также нужно будет изменить имя, поскольку идентификаторState
уже занято State
оболочка свойств - поэтому я просто изменил ее на StateEntity
)
@State var states: [StateEntity] = [
StateEntity(name: "Oregon", hasBeenSeen: true),
// ... etc
]
Однако этого недостаточно, поскольку, когда вы передаете элемент states
массив (a StateEntity
value) в дочернее представление, вы просто передаете копию.
Для этого вам понадобится привязка. Привязка позволяет дочерним представлениям изменять свойства состояния родительских представлений без владения данными. Итак, свойство дочернего представления должно использовать@Binding
оболочка свойства:
struct StateCell: View {
@Binding var state: StateEntity
// ...
}
SwiftUI упростил получение привязки государственного свойства с помощью прогнозируемого значения, которое в данном случае $states
.
Однако вам нужно передать привязку не ко всему массиву, а к определенному элементу этого массива. Это, к сожалению (и довольно досадно), немного сложнее. Вам нужно получить индекс элемента и, учитывая индекс, получить доступ к привязке следующим образом:$state[index]
.
Один из способов - сделать ForEach
по индексам states
:
var body: some View {
NavigationView {
List {
ForEach(states.indices) { index in
StateCell(state: self.$states[index])
}
}.navigationBarTitle(Text("States"))
}
}