【发布时间】:2021-01-30 07:34:22
【问题描述】:
我正在尝试在 SwiftUI 中创建一个滑块(与原生 Slider 风格相同,但最终具有更多功能)。在下面的 gif 中,我的滑块位于顶部,SwiftUI 的原生滑块位于底部,两者的范围和值都相同。当我拖动原生滑块时,我的视图会更新,但是当我快速前后拖动时,圆圈会闪烁。请问有没有办法防止这种频闪? gif 不是很清楚,所以我提供了重现的代码。任何指向正确方向的指针表示赞赏!
这是我的滑块的代码:
struct BarSlider: View {
@Binding var value: CGFloat
var range: ClosedRange<CGFloat>
var body: some View {
GeometryReader { geo in
ZStack {
HStack(spacing: 0) {
Rectangle()
.fill(Color.red)
.frame(width: $value.wrappedValue.map(from: range, to: 0...geo.size.width))
Rectangle()
.fill(Color.green)
}
HStack {
Circle()
.frame(width: 30, height: 30)
.offset(x: valueForKnob(geometry: geo))
Spacer()
}
}
.background(Color.blue)
}
}
private func valueForKnob(geometry: GeometryProxy) -> CGFloat {
$value.wrappedValue.map(from: range, to: 0...geometry.size.width) - (30 * valueAsPercent())
}
private func valueAsPercent() -> CGFloat {
let percent = ((value - range.lowerBound) / (range.upperBound - range.lowerBound) * 100) / 100
return percent.clamped(to: 0...1)
}
}
这是两个滑块:
struct ContentView: View {
@State private var amount = CGFloat(100)
var body: some View {
VStack {
BarSlider(value: $amount, range: 100...1000)
.frame(height: 100)
Slider(value: $amount, in: 100...1000)
}
}
}
还有这些扩展:
extension CGFloat {
func map(from: ClosedRange<CGFloat>, to: ClosedRange<CGFloat>) -> CGFloat {
let value = self.clamped(to: from)
let fromRange = from.upperBound - from.lowerBound
let toRange = to.upperBound - to.lowerBound
let result = (((value - from.lowerBound) / fromRange) * toRange) + to.lowerBound
return result
}
}
extension Comparable {
func clamped(to limits: ClosedRange<Self>) -> Self {
return min(max(self, limits.lowerBound), limits.upperBound)
}
}
【问题讨论】: