Я очень новичок в Combine, и я пытаюсь получить два ползунка SwiftUI для обновления до и от третьего значения, которое представляет «единственный источник правды» для их соответствующих значений.
Каждый ползунок имеет диапазон от 0 до 1, но использует другую функцию для определения его значения. В приведенном ниже примере, если истинное значение равно 0,5, первый ползунок устанавливает и получает его непосредственно (0,5), тогда как второй ползунок использует значение в квадрате (0,25).
Пример работает, но у меня складывается впечатление, что это не совсем правильный способ сделать это. Я получаю бесконечную рекурсию, если в Модели удалены защитные утверждения. Может кто-нибудь показать мне правильный способ сделать это? Спасибо!
Вот модель:
import SwiftUI
class Model : ObservableObject{
@Published var trueValue: CGFloat = 0{
didSet{
slider1Value = trueValue
slider2Value = trueValue * trueValue
}
}
@Published var slider1Value: CGFloat = 0{
didSet{
guard oldValue != slider1Value else { return }
trueValue = slider1Value
}
}
@Published var slider2Value: CGFloat = 0{
didSet{
guard oldValue != slider2Value else { return }
trueValue = slider2Value.squareRoot()
}
}
}
Вот ContentView:
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
GeometryReader{ geometry in
VStack{
ProportionalSlider(value: self.$model.slider1Value, width: geometry.size.width - 20)
.frame(width: geometry.size.width, height: 18)
ProportionalSlider(value: self.$model.slider2Value, width: geometry.size.width - 20)
.frame(width: geometry.size.width, height: 18)
}
}
}
}
А вот ProportionalSlider:
struct ProportionalSlider: View {
@Binding var value: CGFloat
var width: CGFloat
var body: some View{
let gesture = DragGesture(minimumDistance: 0)
.onChanged({ mouse in
let clamped = min(self.width, max(0, mouse.location.x))
self.value = clamped/self.width
})
return GeometryReader{ geometry in
ZStack{
ZStack(alignment: .leading){
Capsule().fill(Color.blue).frame(width: self.width, height: 15)
.gesture(gesture)
Capsule().fill(Color.red).frame(width: self.value * self.width, height: 15)
.gesture(gesture)
}
}
}
}
}