Skip to content

Instantly share code, notes, and snippets.

@ccwasden
Last active April 7, 2020 18:11
Show Gist options
  • Save ccwasden/a822b48238498dd8c8dddaa64238c5ac to your computer and use it in GitHub Desktop.
Save ccwasden/a822b48238498dd8c8dddaa64238c5ac to your computer and use it in GitHub Desktop.
Multiselect using a custom property wrapper - Modified from child view through a Binding
//
// Author: Chase Wasden
// Website: https://gist.github.com/ccwasden
// Licensed under MIT license https://opensource.org/licenses/MIT
//
import SwiftUI
struct Fruit: Identifiable {
let name: String
var isSelected: Bool
var id: String { name }
}
struct FruitList: View {
@BindableArray var fruits = [
Fruit(name: "Apple", isSelected: false),
Fruit(name: "Banana", isSelected: true),
Fruit(name: "Kumquat", isSelected: false),
]
var body: some View {
VStack {
Text("Select Fruits (\(fruits.filter { $0.isSelected }.count))")
List($fruits) { (fruit: Binding<Fruit>) in
FruitRow(fruit: fruit)
}
}
}
struct FruitRow: View {
@Binding var fruit: Fruit
var body: some View {
Button(action: { self.fruit.isSelected.toggle() }) {
HStack {
Text(fruit.isSelected ? "☑" : "☐")
Text(fruit.name)
}
}
}
}
}
// ----------- The Reusable Magic ----------- //
extension Binding: Identifiable where Value: Identifiable {
public var id: Value.ID {
return wrappedValue.id
}
}
@propertyWrapper
struct BindableArray<Value> : DynamicProperty {
@State var storage: [Value]
init(wrappedValue value: [Value]) {
self._storage = State(initialValue: value)
}
public var wrappedValue: [Value] {
get { storage }
nonmutating set { storage = newValue }
}
public var projectedValue: [Binding<Value>] {
var bindings = [Binding<Value>]()
for (i, item) in storage.enumerated() {
bindings.append(Binding(
get: { item },
set: { self.wrappedValue[i] = $0 }
))
}
return bindings
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment