[英]SwiftUI: How can I adjust the circle Slider/Picker
I would like to enable values to be entered using a Circle Slider.我想启用使用圆形滑块输入的值。 Before that I had implemented the Input of values with a Picker.
在此之前,我已经使用 Picker 实现了值的输入。 But now I have a little Problem with the Circle Slider.
但是现在我对圆形滑块有一个小问题。 I want to adjust the values that can be selected.
我想调整可以选择的值。 Now I can select values from 0% to 100%.
现在我可以选择从 0% 到 100% 的值。 How can I display the values from 21% to 90% but from 50% the values should appear in „10 steps“.
如何显示从 21% 到 90% 的值,但从 50% 开始,这些值应该出现在“10 个步骤”中。 (21%,22%,23%… 50%, 60%, 70%, 80%, 90%) Is it possible to set the starting value to 32?
(21%,22%,23%... 50%, 60%, 70%, 80%, 90%) 是否可以将起始值设置为 32?
The Code from the new Circle Slider:来自新圆形滑块的代码:
struct Slider: View {
@State var size = UIScreen.main.bounds.width - 100
@State var progress: CGFloat = 0
@State var angle: Double = 0
var body: some View {
VStack {
ZStack {
Circle()
.stroke(Color("CircleSlider"), style: StrokeStyle(lineWidth: 55, lineCap: .round, lineJoin: .round))
.frame(width: size, height: size)
Circle()
.trim(from: 0, to: progress)
.stroke(Color("CircleSliderfill"), style: StrokeStyle(lineWidth: 55, lineCap: .butt))
.frame(width: size, height: size)
.rotationEffect(.init(degrees: -90))
Circle()
.fill(Color("CircleSlider"))
.frame(width: 55, height: 55)
.offset(x: size / 2)
.rotationEffect(.init(degrees: -90))
Circle()
.fill(Color.white)
.frame(width: 55, height: 55)
.offset(x: size / 2)
.rotationEffect(.init(degrees: angle))
.gesture(DragGesture().onChanged(onDrag(value:)))
.rotationEffect(.init(degrees: -90))
//example from 0 to 100%
Text(String(format: "%.0f", progress * 100) + "%")
}
}
}
func onDrag(value: DragGesture.Value) {
let vector = CGVector(dx: value.location.x, dy: value.location.y)
let radians = atan2(vector.dy - 27.5, vector.dx - 27.5
var angle = radians * 180 / .pi
if angle < 0 {
angle = 360 + angle
}
withAnimation(Animation.linear(duration: 0.15)) {
let progress = angle / 360
self.progress = progress
self.angle = Double(angle)
}
}
}
The Code from the old Picker:来自旧 Picker 的代码:
struct ValueO2: View {
@State var valueIndexO2MOD_0 = 32
@State var valueArray : [Int] = []
var body: some View {
VStack{
Section {
Text("O2"))
Picker("",selection: $valueIndexO2MOD_0) {
ForEach(valueArray, id: \.self){ value in
Text("\(value) %")
}
}
}
.labelsHidden()
}.onAppear{
self.initPickerIndex()
}
}
func initPickerIndex(){
valueArray = []
for index1 in 21..<50 {
valueArray.append(index1)
}
for index2 in 1...5{
valueArray.append(40 + index2 * 10)
}
}
}
You can do that with some simple modifications:您可以通过一些简单的修改来做到这一点:
If you want to change the Text in "10 steps" you can do this:如果您想在“10 个步骤”中更改文本,您可以这样做:
Text(String(format: "%.0f", progress >= 0.5 ? round(progress * 10) * 10 : progress * 100) + "%")
To change the actual value in "10 steps", you need to change the calculation of your progress and angle slightly:要更改“10步”中的实际值,您需要稍微更改进度和角度的计算:
func onDrag(value: DragGesture.Value) {
let vector = CGVector(dx: value.location.x, dy: value.location.y)
let radians = atan2(vector.dy - 27.5, vector.dx - 27.5)
var angle = radians * 180 / .pi
if angle < 0 {
angle = 360 + angle
}
var progress = angle / 360
if progress >= 0.5 {
// Round & update angle
progress = round(progress * 10) / 10
angle = progress * 360
}
withAnimation(Animation.linear(duration: 0.15)) {
self.progress = progress
self.angle = Double(angle)
}
}
To set a start value you can use a simple function:要设置起始值,您可以使用一个简单的函数:
func setStartValue(value: CGFloat) {
withAnimation(Animation.linear(duration: 0.15)) {
progress = value
angle = Double(progress * 360)
}
}
You can call it when the view appears by using the .onAppear
modifier:您可以使用
.onAppear
修饰符在视图出现时调用它:
VStack {
// your slider
}.onAppear {
setStartValue(value: 0.32)
}
EDIT: Limit range from 21% to 90%编辑:限制范围从 21% 到 90%
func onDrag(value: DragGesture.Value) {
let vector = CGVector(dx: value.location.x, dy: value.location.y)
let radians = atan2(vector.dy - 27.5, vector.dx - 27.5)
var angle = radians * 180 / .pi
if angle < 0 {
angle = 360 + angle
}
var progress = angle / 360
// "10 Steps"
if progress >= 0.5 {
// Round & update angle
progress = round(progress * 10) / 10
angle = progress * 360
}
// Boundaries (21% to 90%)
let minValue: CGFloat = 0.21
let maxValue: CGFloat = 0.9
if progress < minValue {
progress = minValue
angle = progress * 360
} else if progress > maxValue {
progress = maxValue
angle = progress * 360
}
withAnimation(Animation.linear(duration: 0.15)) {
self.progress = progress
self.angle = Double(angle)
}
}
I think that the idea of selecting elements from an array using the slider is interesting.我认为使用滑块从数组中选择元素的想法很有趣。 So here is a second answer how this can be achieved:
所以这是如何实现的第二个答案:
struct CircularSlider: View {
@State var size = UIScreen.main.bounds.width - 100
@State var progress: CGFloat = 0
@State var angle: Double = 0
let validValues = Array(21...90) // [1.2, 1.3, 1.4, 1.5, 1.6]
@State var selectedValue: Double = 31
var body: some View {
VStack {
ZStack {
Circle()
.stroke(Color(.lightGray), style: StrokeStyle(lineWidth: 55, lineCap: .round, lineJoin: .round))
.frame(width: size, height: size)
Circle()
.trim(from: 0, to: progress)
.stroke(Color(.systemGreen), style: StrokeStyle(lineWidth: 55, lineCap: .butt))
.frame(width: size, height: size)
.rotationEffect(.init(degrees: -90))
Circle()
.fill(Color(.lightGray))
.frame(width: 55, height: 55)
.offset(x: size / 2)
.rotationEffect(.init(degrees: -90))
Circle()
.fill(Color.white)
.frame(width: 55, height: 55)
.offset(x: size / 2)
.rotationEffect(.init(degrees: angle))
.gesture(DragGesture().onChanged(onDrag(value:)))
.rotationEffect(.init(degrees: -90))
// Text(String(format: "%.1f", selectedValue))
Text("\(selectedValue)")
}
}.onAppear {
setStartValue(value: selectedValue)
}
}
private func onDrag(value: DragGesture.Value) {
let vector = CGVector(dx: value.location.x, dy: value.location.y)
let radians = atan2(vector.dy - 27.5, vector.dx - 27.5)
var angle = radians * 180 / .pi
if angle < 0 {
angle = 360 + angle
}
let progress = angle / 360
// Select Value in Array
selectValue(progress: progress)
withAnimation(Animation.linear(duration: 0.15)) {
self.progress = progress
self.angle = Double(angle)
}
}
private func selectValue(progress: CGFloat) {
let segments: CGFloat = CGFloat(validValues.count - 1)
let indexLimit: CGFloat = 100 / segments
let index = Int(round((progress / indexLimit) * 100))
selectedValue = Double(validValues[index])
}
private func setStartValue(value: Double) {
// Transform value to progress
if let index = validValues.firstIndex(of: Int(value)) {
progress = CGFloat(index) / CGFloat(validValues.count)
print(progress)
withAnimation(Animation.linear(duration: 0.15)) {
self.progress = CGFloat(progress)
self.angle = Double(self.progress * 360)
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.