Reputation: 167
I'm trying to change the checkmark image on listview
row selection, but I'm not getting expected result from selection.
Below code I'm creating listview
from the array todo items and added tapGesture
to the row. When I'm selecting row I can able to change the completed
value but not reflecting that on UI.
struct ContentView: View {
@State var items: [Todo] = todoItems
var body: some View {
List(items, id: \.self) { item in
Row(item: item) { item in
item.completed.toggle()
print(item.completed)
}
}
}
}
struct Row: View {
let item: Todo
var onTap: ((_ item: Todo) -> Void)?
var body: some View {
HStack {
Image(systemName: item.completed ? "checkmark.square.fill" : "squareshape" )
.foregroundColor(item.completed ? .green : .gray)
Text(item.title).font(.headline).foregroundColor(.secondary)
}.onTapGesture {
onTap?(item)
}
}
}
class Todo: Hashable {
static func == (lhs: Todo, rhs: Todo) -> Bool {
lhs.title == rhs.title
}
var title: String
var completed: Bool
init(title: String, completed: Bool) {
self.title = title
self.completed = completed
}
func hash(into hasher: inout Hasher) {
hasher.combine(title)
}
}
let todoItems = [
Todo(title: "$300", completed: false),
Todo(title: "$550", completed: false),
Todo(title: "$450", completed: false)
]
Upvotes: 1
Views: 3384
Reputation: 30341
You can make Todo
a struct
. For data like this, it is much more preferable for it to be a struct
rather than a class
.
The item
also doesn't need to be passed down, since you already get it in the List
. I also used the $
syntax within for $items
, so $item
is a Binding
and you therefore can mutate item
. Changing item
is changing that element in @State
variable items
, therefore a view update occurs.
Your implementation for Equatable
and Hashable
on Todo
was incorrect - because otherwise the view won't update if a Todo
instance is the same, even with a different completed
value. I added Identifiable
to Todo
anyway, so you can implicitly identify by id
.
Code:
struct ContentView: View {
@State var items: [Todo] = todoItems
var body: some View {
List($items) { $item in
Row(item: item) {
item.completed.toggle()
}
}
}
}
struct Row: View {
let item: Todo
let onTap: (() -> Void)?
var body: some View {
HStack {
Image(systemName: item.completed ? "checkmark.square.fill" : "squareshape" )
.foregroundColor(item.completed ? .green : .gray)
Text(item.title).font(.headline).foregroundColor(.secondary)
}.onTapGesture {
onTap?()
}
}
}
struct Todo: Hashable, Identifiable {
let id = UUID()
var title: String
var completed: Bool
init(title: String, completed: Bool) {
self.title = title
self.completed = completed
}
}
Upvotes: 1