Skip to content

Instantly share code, notes, and snippets.

@ccwasden
Created April 7, 2020 17:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ccwasden/3973717f18d3fd87fab083350532a195 to your computer and use it in GitHub Desktop.
Save ccwasden/3973717f18d3fd87fab083350532a195 to your computer and use it in GitHub Desktop.
SwiftUI Multiselect
//
// Author: Chase Wasden
// Website: https://gist.github.com/ccwasden
// Licensed under MIT license https://opensource.org/licenses/MIT
//
import SwiftUI
struct Fruit: Selectable {
let name: String
var isSelected: Bool
var id: String { name }
}
struct FruitList: View {
@State var fruits = [
Fruit(name: "Apple", isSelected: true),
Fruit(name: "Banana", isSelected: false),
Fruit(name: "Kumquat", isSelected: true),
]
var body: some View {
VStack {
Text("Number selected: \(fruits.filter { $0.isSelected }.count)")
Multiselect(items: $fruits) { fruit in
HStack {
Text(fruit.name)
Spacer()
if fruit.isSelected {
Image(systemName: "checkmark")
}
}
}
}
}
}
// ---------------------- The Reusable Magic ---------------------- //
protocol Selectable: Identifiable {
var name: String { get }
var isSelected: Bool { get set }
}
struct Multiselect<T: Selectable, V: View>: View {
@Binding var items: [T]
var rowBuilder: (T) -> V
var body: some View {
List(items) { item in
Button(action: { self.items.toggleSelected(item) }) {
self.rowBuilder(item)
}
}
}
}
extension Array where Element: Selectable {
mutating func toggleSelected(_ item: Element) {
if let index = firstIndex(where: { $0.id == item.id }) {
var mutable = item
mutable.isSelected.toggle()
self[index] = mutable
}
}
}
@ccwasden
Copy link
Author

ccwasden commented Apr 7, 2020

If your data is coming from an ObservableObject (eg. ViewModel), the list view would look like this instead:

struct FruitList: View {

    @ObservedObject var viewModel: ViewModel

    var body: some View {
        VStack {
            Text("Number selected: \(viewModel.fruits.filter { $0.isSelected }.count)")
            Multiselect(items: $viewModel.fruits) { fruit in
                HStack {
                    Text(fruit.name)
                    Spacer()
                    if fruit.isSelected {
                        Image(systemName: "checkmark")
                    }
                }
            }
        }
    }
}

@jagan510710
Copy link

Thanks, Why we are getting blue color by tapping on row. How to remove that color?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment