Как получить два ползунка SwiftUI для обновления до и от третьего значения, которое представляет «единый источник правды» для их соответствующих значений - PullRequest
0 голосов
/ 09 апреля 2020

Я очень новичок в 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)
                }
            }
        }
    }
}

1 Ответ

0 голосов
/ 09 апреля 2020

Используйте одно свойство @Published и одно вычисляемое свойство:

class Model: ObservedObject {
    @Published var linearValue: CGFloat = 0

    var quadraticValue: CGFloat {
        get { linearValue * linearValue }
        set { linearValue = sqrt(newValue) }
    }
}

Привязать один ползунок к $model.linearValue, а другой - к $model.quadraticValue.

...