Last active
April 7, 2020 13:58
-
-
Save ccwasden/9932edba37ed3f77f46c1e95402de7fe to your computer and use it in GitHub Desktop.
Multiselect using ObservableObject with child array - Modified from child view through a Binding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Cheese: Identifiable { | |
let name: String | |
var isSelected: Bool | |
var id: String { name } | |
} | |
class ViewModel: ObservableObject { | |
@Published var cheeses = [ | |
Cheese(name: "Brie", isSelected: false), | |
Cheese(name: "Cheddar", isSelected: true), | |
Cheese(name: "Gouda", isSelected: false), | |
] | |
} | |
struct CheeseList: View { | |
@ObservedObject var viewModel = ViewModel() | |
var body: some View { | |
VStack { | |
Text("Select Cheeses (\(viewModel.cheeses.filter { $0.isSelected }.count))") | |
BindingList(items: $viewModel.cheeses) { cheese in | |
CheeseRow(cheese: cheese) | |
} | |
} | |
} | |
} | |
struct CheeseRow: View { | |
@Binding var cheese: Cheese | |
var body: some View { | |
Button(action: { self.cheese.isSelected.toggle() }) { | |
HStack { | |
Text(cheese.isSelected ? "☑" : "☐") | |
Text(cheese.name) | |
} | |
} | |
} | |
} | |
// ----------- The Reusable Magic ----------- // | |
struct BindingList<T: Identifiable, V: View>: View { | |
@BindableArray var items: Binding<[T]> | |
let rowBuilder: ((Binding<T>) -> V) | |
var body: some View { | |
List($items, rowContent: rowBuilder) | |
} | |
} | |
extension Binding: Identifiable where Value: Identifiable { | |
public var id: Value.ID { | |
return wrappedValue.id | |
} | |
} | |
@propertyWrapper | |
struct BindableArray<Value> : DynamicProperty { | |
@Binding var storage: [Value] | |
init(wrappedValue value: Binding<[Value]>) { | |
self._storage = value | |
} | |
public var wrappedValue: Binding<[Value]> { | |
get { _storage } | |
nonmutating set { storage = newValue.wrappedValue } | |
} | |
public var projectedValue: [Binding<Value>] { | |
var bindings = [Binding<Value>]() | |
for (i, item) in storage.enumerated() { | |
bindings.append(Binding( | |
get: { item }, | |
set: { self.wrappedValue[i].wrappedValue = $0 } | |
)) | |
} | |
return bindings | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment