您可以将所有State 变量的绑定存储在Array<Binding<Double>> 类型的数组中。如果您愿意,这允许您添加更多滑块而无需更多代码。
struct Sliders: View {
@State var value1 = 100.0
@State var value2 = 0.0
@State var value3 = 0.0
@State var value4 = 0.0
var body: some View {
// add all bindings which you want to synchronize
let allBindings = [$value1, $value2, $value3, $value4]
return VStack {
Button(action: {
// Manually setting the values does not change the values such
// that they sum to 100. Use separate algorithm for this
self.value1 = 10
self.value2 = 40
}) {
Text("Test")
}
Text("\(value1)")
synchronizedSlider(from: allBindings, index: 0)
Text("\(value2)")
synchronizedSlider(from: allBindings, index: 1)
Text("\(value3)")
synchronizedSlider(from: allBindings, index: 2)
Text("\(value4)")
synchronizedSlider(from: allBindings, index: 3)
}.padding()
}
func synchronizedSlider(from bindings: [Binding<Double>], index: Int) -> some View {
return Slider(value: synchronizedBinding(from: bindings, index: index),
in: 0...100)
}
func synchronizedBinding(from bindings: [Binding<Double>], index: Int) -> Binding<Double> {
return Binding(get: {
return bindings[index].wrappedValue
}, set: { newValue in
let sum = bindings.indices.lazy.filter{ $0 != index }.map{ bindings[$0].wrappedValue }.reduce(0.0, +)
// Use the 'sum' below if you initially provide values which sum to 100
// and if you do not set the state in code (e.g. click the button)
//let sum = 100.0 - bindings[index].wrappedValue
let remaining = 100.0 - newValue
if sum != 0.0 {
for i in bindings.indices {
if i != index {
bindings[i].wrappedValue = bindings[i].wrappedValue * remaining / sum
}
}
} else {
// handle 0 sum
let newOtherValue = remaining / Double(bindings.count - 1)
for i in bindings.indices {
if i != index {
bindings[i].wrappedValue = newOtherValue
}
}
}
bindings[index].wrappedValue = newValue
})
}
}
如果您只想同步value1/value2 和value3/value4 的滑块,您可以将body 中的代码更改为:
let bindings12 = [$value1, $value2]
let bindings34 = [$value3, $value4]
return VStack {
Text("\(value1)")
synchronizedSlider(from: bindings12, index: 0)
Text("\(value2)")
synchronizedSlider(from: bindings12, index: 1)
Text("\(value3)")
synchronizedSlider(from: bindings34, index: 0)
Text("\(value4)")
synchronizedSlider(from: bindings34, index: 1)
}.padding()