I have the following List:
List(selection: self.$selectionKeeper) {
ForEach(self.items, id: \.self) { name in
Text(name)
}
}
.environment(\.editMode, .constant(.active))
How can I get a callback each time an item is (de)selected? I know I can listen for changes in selectionKeeper, but I thought there might be a better way
Yes, the easiest way is to use onChange (or onReceive in iOS 13) to monitor changes to selectionKeeper:
List(selection: self.$selectionKeeper) {
ForEach(0..<5, id: \.self) { item in
Text("\(item)")
}
}
.environment(\.editMode, .constant(.active))
.onChange(of: selectionKeeper) { selectedItems in
print(selectedItems)
}
If you want to do it in another way, you can create a custom binding:
struct ContentView: View {
@State private var selectionKeeper = Set<Int>()
var body: some View {
List(selection: .init(
get: {
selectionKeeper
},
set: {
selectionKeeper = $0
selectionCallback($0)
}
)) {
ForEach(0..<5, id: \.self) { item in
Text("\(item)")
}
}
.environment(\.editMode, .constant(.active))
}
func selectionCallback(_ selectedItems: Set<Int>) {
print(selectedItems)
}
}
You can also extract the binding as a computed property:
var listBinding: Binding<Set<Int>> {
.init(
get: {
selectionKeeper
},
set: {
selectionKeeper = $0
selectionCallback($0)
}
)
}
List(selection: listBinding) { ... }
The onChange solution is simpler and more useful when you only need to react to changes to a specific variable. However, with a custom binding you get much more flexibility (you can change both get and set).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With