Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select Multiple Items in SwiftUI List

Tags:

swiftui

In UIKit you can select multiple rows of a UITableView by using allowsMultipleSelection - can this be done with the List in SwiftUI?

like image 999
Brandon Bradley Avatar asked Jul 13 '19 20:07

Brandon Bradley


People also ask

How do you select multiple items in Swift?

The only way to get multiple selection in SwiftUI right now is by using EditButton . However, that's not the only instance you might want to use multiple selection, and it would probably confuse users if you used EditButton multiple selection when you're not actually trying to edit anything.

How do you select multiple items in a list on Iphone?

Rather than using a sub-menu to put the items in “Select” mode and then ticking the circles that appear in each row, you can just swipe two fingers down the list to select every item in the list that your fingers touch.

How do I select multiple items in Xcode?

Click-and-drag creates a selection consisting of whatever you drag over, so Control-Shift-Click-and-drag adds what you drag over to the existing selection.


Video Answer


3 Answers

The only way to get multiple selection in SwiftUI right now is by using EditButton. However, that's not the only instance you might want to use multiple selection, and it would probably confuse users if you used EditButton multiple selection when you're not actually trying to edit anything.

I assume what you're really looking for is something like this:

enter image description here

Below is the code I wrote to create this:

struct MultipleSelectionList: View {
    @State var items: [String] = ["Apples", "Oranges", "Bananas", "Pears", "Mangos", "Grapefruit"]
    @State var selections: [String] = []

    var body: some View {
        List {
            ForEach(self.items, id: \.self) { item in
                MultipleSelectionRow(title: item, isSelected: self.selections.contains(item)) {
                    if self.selections.contains(item) {
                        self.selections.removeAll(where: { $0 == item })
                    }
                    else {
                        self.selections.append(item)
                    }
                }
            }
        }
    }
}
struct MultipleSelectionRow: View {
    var title: String
    var isSelected: Bool
    var action: () -> Void

    var body: some View {
        Button(action: self.action) {
            HStack {
                Text(self.title)
                if self.isSelected {
                    Spacer()
                    Image(systemName: "checkmark")
                }
            }
        }
    }
}
like image 197
graycampbell Avatar answered Nov 08 '22 20:11

graycampbell


First add this to your view

@State var selectedItems = Set<UUID>()

The type of the Set depends on the type you use to id: the items in the ForEach

Next declare the List

List(selection: $selectedItems) {
    ForEach(items, id: \.id) { item in
        Text("\(item.name)")
    }
}

Now whatever you select gets added to the selectedItems Set remember to clear it out after you use it.

like image 22
Jevon Charles Avatar answered Nov 08 '22 20:11

Jevon Charles


I created a custom ToggleStyle as follows:

import SwiftUI


enum Fruit: String, CaseIterable, Hashable {
    case apple = "Apple"
    case orange = "Orange"
    case banana = "Banana"
}

struct ContentView: View {

    @State var fruits = [Bool](repeating: false, count: Fruit.allCases.count)

    var body: some View {
        Form{
            ForEach(0..<fruits.count, id:\.self){i in
                Toggle(isOn: self.$fruits[i]){
                    Text(Fruit.allCases[i].rawValue)
                }.toggleStyle(CheckmarkToggleStyle())
            }
        }
    }
}

struct CheckmarkToggleStyle: ToggleStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        HStack {
            Button(action: { withAnimation { configuration.$isOn.wrappedValue.toggle() }}){
                HStack{
                    configuration.label.foregroundColor(.primary)
                    Spacer()
                    if configuration.isOn {
                        Image(systemName: "checkmark").foregroundColor(.primary)
                    }
                }
            }
        }
    }
}

like image 31
simibac Avatar answered Nov 08 '22 22:11

simibac