I'm struggling to implement a custom view which can take Binding as an argument and implement two-way updates of that value.
So basically I'm implementing my custom slider and want its initializer to be like this:
MySlider(value: <Binding<Float>)
What I'm struggling with:
- How do I subscribe to remote updates of the binding value so that I can update the view's state?
- Is there any nice way to bind a Binding with @State property?
Here's my current implementation so far which is not perfect.
struct MySlider: View {
@Binding var selection: Float?
@State private var selectedValue: Float?
init(selection: Binding<Float?>) {
self._selection = selection
// https://stackoverflow.com/a/58137096
_selectedValue = State(wrappedValue: selection.wrappedValue)
}
var body: some View {
HStack(spacing: 3) {
ForEach(someValues) { (v) in
Item(value: v,
isSelected: v == self.selection)
.onTapGesture {
// No idea how to do that other way so I don't have to set it twice
self.selection = v
self.selectedValue = v
}
}
}
}
}
Edit 1:
I suppose my problem is that the underlying model object comes from Core Data and wasn't owned by any SwiftUI view which would observe its changes. The model object was owned by the UIKit ViewController and I was passing only a Binding to the SwiftUI view which is not enough.
My solution now is to pass the model object also to the SwiftUI View so that it can marked it as an @ObservedObject
.
struct MySlider<T>: View where T: ObservableObject {
@ObservedObject var object: T
@Binding var selection: Float?
var body: some View {
return ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 3) {
ForEach(values) { (v) in
Item(value: v,
isSelected: v == self.selection)
.onTapGesture {
self.selection = v
}
}
}
}
}
}