In an iOS Project, i have to implement a view controller that allows to pick a float value using a slider and a text field at the same time. it should have the following behaviour:
- whenever a number is typed in the text field, the slider should update it's value to the typed float number
- whenever the slider is dragged it should update the text field with the slider value
Current ideas is as follows:
I have two propertys in the view model, the actual value and the value text. Whenever the value is updated i update the text within the view model. Both the text field and the slider change only the value. But then i have a kind of 'cyclic' dependency: text field updates the view models value, which updates the view models text, which is bound to the textfield where we just type the value. This leads to buggy behaviour of the text field. I tried to work around with the isFirstResponder property, that works better, but does not seem best practise, plus it's not as intended. Is there a way bind the enabledProperty of the slider to isFirstResponder of the text field? That would also work
Bindings in VC:
layout.valueTextField.reactive.text <~ viewModel.valueText.map( { text in
if !self.layout.valueTextField.isFirstResponder {
return text
}
return self.layout.valueTextField.text ?? ""
}
)
viewModel.value <~ layout.valueSlider.reactive.values
layout.valueSlider.reactive.value <~ viewModel.value
viewModel.value <~ layout.valueTextField.reactive.continuousTextValues.map({ textValue in
if let t = textValue {
if let parsed = Float(t) {
return parsed
}
}
return viewModel.value.value
})
My view Model:
import ReactiveSwift
class ValuePickerViewModel {
var valueText: MutableProperty<String>
var value: MutableProperty<Float>
let minValue: Float
let maxValue: Float
let unit: String
init(initialValue: Float, formatter: FloatFormatter, minValue: Float, maxValue: Float, unit: String) {
self.value = MutableProperty(initialValue)
self.valueText = MutableProperty(formatter.format(value: initialValue))
self.valueText <~ self.value.map({value in
formatter.format(value: value)
}
)
self.minValue = minValue
self.maxValue = maxValue
self.unit = unit
}
}