slider - SwiftUI 中相互关联的多个滑块
问题描述
我想知道是否有人可以帮助我。
在我正在开发的应用程序中,我需要将一个值分成四个不同的区域,我想通过四个滑块来实现,这些滑块控制每个区域的百分比。
对于每一个Slider
,我都创建了一个@State private var sliderAValue = 25
并将它们绑定到滑块上Slider(value: $sliderAValue, in: 0...100)
显然,当我更改任何滑块的值时,其他值也应该更改,以便总百分比始终为 100。
但更重要的是,其他三个值之间的比率应该是相同的:例如。如果原来的分割是 30 : 30 : 20 : 20 并且用户将第三个元素更改为 40%,那么新的分割应该变成 22.5 : 22.5 : 40 : 15。
对变量应用 adidSet
或 a似乎没有任何效果,但我显然需要将原始比率存储在某处并自动更新它们。 willSet
State
有任何想法吗?
解决方案
您可以将所有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()
推荐阅读
- python - 如何找到与月份对应的单词并将其替换为数字?
- llvm - 识别函数是否在 LLVM IR 中内联
- angular10 - 如何知道用户何时离开您的 Angular 应用程序
- npm - 如何将 npm 包从 artifactory 镜像到 verdaccio?
- cordova - 在科尔多瓦应用程序中加载白屏
- r - R中的层次聚类
- exit - EasyPHP 17.0 HTTP 服务器警告和通知
- r - 过滤器向量(读取最近的文件名)
- arduino - 带有 LTC6820 的长距离 Arduino 多 NFC 读取器 RC522
- intellij-idea - IntelliJ Idea 忽略 Maven 默认配置文件