admin管理员组文章数量:1122832
I created a simple slider that controls the position of a red circle on the screen within a predefined area. Moving the circle on the screen also moves the slider knob. However, the slider knob has a limited range of movement, from -1.0 to 1.0. When the circle crosses the blue border, the slider logic prevents the knob from sliding further to match the circle's new position.
I’ve been struggling with this issue for days and have tried different approaches, but none have met my requirements. I need to know the logical way (or ways) to handle situations like this, where the slider reaches its maximum range and cannot respond to further movement. How can this issue be resolved in a way that addresses the exhausted slider position rather than preventing it from happening?
PS: I have to say, this extra movement of the circle could be any value, whether big or small.
Also: Slider value of +1.0 means the circle is inside the boundary on the right side, any extra drag of circle beyond that point would still keep the slider at +1.0, but now this +1.0 would correspond to the circle being outside the boundary. While slider value of -1.0 means the boundary on the left side.
Code for iOS 15.0, macOS 12.0
import SwiftUI
struct ContentView: View {
private let maxCanvasVisibilitySize: CGSize = CGSize(width: 400.0, height: 300.0)
private let circleSize: CGSize = CGSize(width: 50.0, height: 50.0)
@State private var maxCanvasImaginarySize: CGSize = CGSize(width: 400.0, height: 300.0)
@State private var circleLastOffset: CGSize = CGSize()
@State private var circleCurrentOffset: CGSize = CGSize()
@State private var circleIsDragging: Bool = Bool()
@State private var percentage: CGFloat = CGFloat()
var body: some View {
VStack {
GeometryReader { geometryValue in
ZStack {
Color.black
Circle()
.fill(Color.red)
.frame(width: circleSize.width, height: circleSize.height)
.offset(circleCurrentOffset)
.gesture(circleDragGesture)
}
.overlay(Rectangle().stroke(Color.blue, lineWidth: 4.0))
}
.frame(width: maxCanvasVisibilitySize.width, height: maxCanvasVisibilitySize.height)
SliderView(percentage: $percentage)
.frame(width: maxCanvasVisibilitySize.width)
}
.padding()
.onChange(of: percentage) { newValue in
if (!circleIsDragging) {
circleCurrentOffset.width = newValue * ((maxCanvasVisibilitySize.width - circleSize.width)/2.0)
circleLastOffset = circleCurrentOffset
}
}
}
private var circleDragGesture: some Gesture {
return DragGesture(minimumDistance: CGFloat.zero, coordinateSpace: .local)
.onChanged() { gestureValue in
circleIsDragging = true
circleCurrentOffset = CGSize(width: gestureValue.translation.width + circleLastOffset.width,
height: gestureValue.translation.height + circleLastOffset.height)
percentage = circleCurrentOffset.width/((maxCanvasVisibilitySize.width - circleSize.width)/2.0)
}
.onEnded() { gestureValue in
circleLastOffset = circleCurrentOffset
circleIsDragging = false
}
}
}
struct SliderView: View {
init(percentage: Binding<CGFloat>) {
self._percentage = percentage
}
@Binding var percentage: CGFloat
@State private var knobLastOffset: CGFloat = CGFloat()
@State private var knobCurrentOffset: CGFloat = CGFloat()
@State private var knobIsDragging: Bool = Bool()
private let knobSize: CGSize = CGSize(width: 50.0, height: 30.0)
@State private var sliderGeometrySize: CGSize = CGSize()
var body: some View {
GeometryReader { geometryValue in
ZStack {
Color.white
Color.blue.opacity(0.75)
.frame(width: knobSize.width)
.offset(x: knobCurrentOffset)
.gesture(knobDragGesture)
}
.onAppear { sliderGeometrySize = geometryValue.size }
.onChange(of: geometryValue.size) { newValue in
sliderGeometrySize = newValue
let upperRangeOffset = (newValue.width - knobSize.width)/2.0
let lowerRangeOffset = -upperRangeOffset
knobCurrentOffset = offsetRegulatorWithPercentage(percentage: percentage, upperRangeOffset: upperRangeOffset, lowerRangeOffset: lowerRangeOffset)
knobLastOffset = knobCurrentOffset
}
}
.frame(height: knobSize.height)
.onChange(of: percentage) { newValue in
if (!knobIsDragging) {
let upperRangeOffset = (sliderGeometrySize.width - knobSize.width)/2.0
let lowerRangeOffset = -upperRangeOffset
knobCurrentOffset = offsetRegulatorWithPercentage(percentage: newValue, upperRangeOffset: upperRangeOffset, lowerRangeOffset: lowerRangeOffset)
knobLastOffset = knobCurrentOffset
}
}
}
private var knobDragGesture: some Gesture {
return DragGesture(minimumDistance: CGFloat.zero, coordinateSpace: .local)
.onChanged() { gestureValue in
knobIsDragging = true
let internalOffset = gestureValue.translation.width + knobLastOffset
let upperRangeOffset = (sliderGeometrySize.width - knobSize.width)/2.0
let lowerRangeOffset = -upperRangeOffset
knobCurrentOffset = offsetRegulator(internalOffset: internalOffset, upperRangeOffset: upperRangeOffset, lowerRangeOffset: lowerRangeOffset)
percentage = knobCurrentOffset / ((sliderGeometrySize.width - knobSize.width)/2.0)
}
.onEnded() { gestureValue in
knobLastOffset = knobCurrentOffset
knobIsDragging = false
}
}
private func offsetRegulator(internalOffset: CGFloat, upperRangeOffset: CGFloat, lowerRangeOffset: CGFloat) -> CGFloat {
if (internalOffset >= .zero) {
if (internalOffset < upperRangeOffset) {
return internalOffset
}
else {
return upperRangeOffset
}
}
else {
if (internalOffset > lowerRangeOffset) {
return internalOffset
}
else {
return lowerRangeOffset
}
}
}
private func offsetRegulatorWithPercentage(percentage: CGFloat, upperRangeOffset: CGFloat, lowerRangeOffset: CGFloat) -> CGFloat {
let internalOffset: CGFloat = percentage * upperRangeOffset
return offsetRegulator(internalOffset: internalOffset, upperRangeOffset: upperRangeOffset, lowerRangeOffset: lowerRangeOffset)
}
}
本文标签: swiftHow can I solve the outofrange percentage issue for slidersStack Overflow
版权声明:本文标题:swift - How can I solve the out-of-range percentage issue for sliders? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736309968a1934209.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论