Reputation: 33
I created the list showing the array of digits. When you select multiple digits and hit the button below, it should tell you the sum of the selected digits.
However, when you select the same digits in the different rows, both of them get checked at a time. I understand that this should be fixed by using UUID, but the final result that I want is the sum of the digits, which is Int. Therefore, I have been lost... Can someone tell me how to make it right, please?
Also, the last row doesn't get checked even when selected for some reason, which is so weird. Here is the link to the gif showing the current situation and the entire code below.
import SwiftUI
struct MultipleSelectionList: View {
@State var items: [Int] = [20, 20, 50, 23, 3442, 332]
@State var selections: [Int] = []
@State var result: Int = 0
var body: some View {
VStack {
List {
ForEach(items, id: \.self) { item in
MultipleSelectionRow(value: item, isSelected: self.selections.contains(item)) {
if self.selections.contains(item) {
self.selections.removeAll(where: { $0 == item })
}
else {
self.selections.append(item)
}
}
}
}
Button(action: {
result = selections.reduce(0, +)
}, label: {
Text("Show result")
})
.padding()
Text("Result is \(result)")
Text("The number of items in the array is \(selections.count)")
.padding()
Spacer()
}
}
}
struct MultipleSelectionRow: View {
var value: Int
var isSelected: Bool
var action: () -> Void
var body: some View {
Button(action: self.action) {
HStack {
Text("\(self.value)")
if self.isSelected {
Spacer()
Image(systemName: "checkmark")
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
MultipleSelectionList()
}
}
Upvotes: 3
Views: 241
Reputation: 29454
Before you look at the code below try making your items: [Int]
into a items: [UUID: Int]
this would mimic having an Identifiable
object.
Programming is about figuring how to make things happen.
import SwiftUI
struct MultipleSelectionList: View {
@State var items: [UUID:Int] = [UUID():20, UUID():20, UUID():50, UUID():23, UUID():3442, UUID():332]
@State var selections: [UUID:Int] = [:]
@State var result: Int = 0
var body: some View {
VStack {
List {
ForEach(items.sorted(by: { $0.1 < $1.1 }), id: \.key) { key, value in
MultipleSelectionRow(value: value, isSelected: self.selections[key] != nil) {
if self.selections[key] != nil {
self.selections.removeValue(forKey: key)
}
else {
self.selections[key] = value
}
}
}
}
Button(action: {
result = selections.values.reduce(0, +)
}, label: {
Text("Show result")
})
.padding()
Text("Result is \(result)")
Text("The number of items in the array is \(selections.count)")
.padding()
Spacer()
}
}
}
struct MultipleSelectionRow: View {
var value: Int
var isSelected: Bool
var action: () -> Void
var body: some View {
Button(action: self.action) {
HStack {
Text("\(self.value)")
if self.isSelected {
Spacer()
Image(systemName: "checkmark")
}
}
}
}
}
struct MultipleSelect_Previews: PreviewProvider {
static var previews: some View {
MultipleSelectionList()
}
}
Upvotes: 1
Reputation: 145
You could just store the index of the items in selections, instead of the actual items.
You could do something like:
ForEach(items.indices) { i in
MultipleSelectionRow(value: items[i], isSelected: self.selections.contains(i)) {
if self.selections.contains(i) {
self.selections.removeAll(where: { $0 == i })
}
else {
self.selections.append(i)
}
}
}
I have not run this so there may be errors but you get the idea.
Upvotes: 2