steve kurogi
steve kurogi

Reputation: 33

How can my selection go right in the list I created in SwiftUI

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.

enter image description here

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

Answers (2)

lorem ipsum
lorem ipsum

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

kkubina
kkubina

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

Related Questions