【问题标题】:How to create a custom slider view in swiftUI?如何在 swiftUI 中创建自定义滑块视图?
【发布时间】:2021-03-03 12:13:51
【问题描述】:

我正在考虑创建一个自定义滑块,它具有渐变背景、表示值的数字以及线条上的白点以显示每一步的位置,我正在寻找的内容如下所示:

我查看了其他几个教程,但我所做的都没有给我我之后的结果,要么是因为元素没有对齐,要么我的代码不像默认滑块那样工作。

一个额外的技巧是我还希望像默认滑块一样快速定位,所以用户不能选择 6.5522 的值,只能选择 6 或 7。

这是我目前拥有的代码:

import SwiftUI

struct CustomSlider: View {
let textColor: Color
let thumbColor: Color
let height: CGFloat
let cornerRadius: CGFloat

@State var lastOffset: CGFloat = 0

@Binding var value: CGFloat

var range: ClosedRange<CGFloat>

var leadingOffset: CGFloat = 5
var trailingOffset: CGFloat = 5



var body: some View {
    GeometryReader { geo in
        VStack {
            ZStack {
                RoundedRectangle(cornerRadius: cornerRadius).fill(LinearGradient(gradient: Gradient(colors: [.paleRed, .mango, .neonYellow, .midGreen]), startPoint: .leading, endPoint: .trailing))
                    .frame(height: height)
                HStack {
                    ForEach(1..<11) { index in
                        Circle()
                            .foregroundColor(.white)
                            .frame(width: height, height: height)
                        if index < 10 {
                            Spacer()
                        }
                    }
                }
                HStack {
                    Circle()
                        .frame(width: height * 2, height: height * 2)
                        .foregroundColor(thumbColor)
                        .offset(x: CGFloat(self.$value.wrappedValue.map(from: self.range, to: 6...(geo.size.width - 6 - 22))))
                        .gesture(
                            DragGesture(minimumDistance: 0)
                                .onChanged { value in

                                    if abs(value.translation.width) < 0.1 {
                                        self.lastOffset = self.$value.wrappedValue.map(from: self.range, to: self.leadingOffset...(geo.size.width - (height * 2) - self.trailingOffset))
                                    }

                                    let sliderPos = max(0 + self.leadingOffset, min(self.lastOffset + value.translation.width, geo.size.width - (height * 2) - self.trailingOffset))
                                    let sliderVal = sliderPos.map(from: self.leadingOffset...(geo.size.width - (height * 2) - self.trailingOffset), to: self.range)

                                    self.value = sliderVal
                                }
                      )
                    Spacer()
                }
            }
            HStack {
                ForEach(1..<11) { index in
                    Text("\(index)")
                        .foregroundColor(.secondaryButtonLightGrey)
                        .font(.custom("Rubik-Medium", size: 16))
                    if index < 10 {
                        Spacer()
                    }
                }
            }
        }


    }
}
}

// 在视图代码中是如何实现的:

CustomSlider(textColor: .textColor, thumbColor: .thumbColor, height: 10, cornerRadius: 10, value: $value, range: 0...10)

如果这些问题真的很简单,我深表歉意,但我对 swiftUI 还是新手,只使用了一个月。

感谢您的建议。

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    我可以回答你问题的第二部分。 要获得整数值,您只需转换该值。 例如:

    self.value = Int(sliderVal)
    

    【讨论】:

      【解决方案2】:

      希望这可能会有所帮助:

      struct CustomSliderView: View {
      @State var slider: Float = 0
      @State var dragGestureTranslation: CGFloat = 0
      @State var lastDragValue: CGFloat = 0
      
      // Slider Draggable Control Settings
      var sliderWidth: CGFloat = 30
      var sliderPadding: CGFloat = 0 // This adds padding to each side
      
      // Stepped Increment
      @State var steppedSlider: Bool = false
      @State var step: Int = 8
      @State var stepInterval: CGFloat = 0
      
      func interval(width: CGFloat, increment: Int) -> CGFloat {
          print("Screen Width: \(width)")
          let result = width * CGFloat(increment) / CGFloat(step)
          return result
      }
      
      func roundToFactor(value: CGFloat, factor: CGFloat) -> CGFloat {
          return factor * round(value / factor)
      }
      
      var body: some View {
          VStack {
              GeometryReader { geometry in
                  // Slider Bar
                  ZStack (alignment: .leading) {
                      Rectangle()
                          .foregroundColor(.blue)
                  } // End of Slider Bar
                  .frame(width: geometry.size.width, height: 3)
                  .padding(.vertical, 15) // Padding to centre the bar
                  
                  // Slider Stacker
                  ZStack (alignment: .top) {
                      if steppedSlider {
                          // Step - Minused the SliderWidth so that it is evenly spaced
                          ForEach(0...step, id: \.self) { number in
                              Rectangle()
                                  .frame(width: 2, height: 10)
                                  .offset(x: interval(width: (geometry.size.width - sliderWidth), increment: number), y: 46)
                              
                              Text("\(number)")
                                  .fontWeight(.bold)
                                  .offset(x: interval(width: (geometry.size.width - sliderWidth), increment: number), y: 64)
                                  
                          }
                      }
                      
                      // Draggable Slider
                      ZStack {
                          Circle()
                              .frame(width: sliderWidth, height: 30)
                      }
                      .offset(x: CGFloat(slider))
                      .padding(.horizontal, sliderPadding)
                  } // End of Slider ZStack
                  .gesture(DragGesture(minimumDistance: 0)
                              .onChanged({ dragValue in
                                  let translation = dragValue.translation
                                  
                                  dragGestureTranslation = CGFloat(translation.width) + lastDragValue
                                  
                                  // Set the start marker of the slider
                                  dragGestureTranslation = dragGestureTranslation >= 0 ? dragGestureTranslation : 0
                                  
                                  // Set the end marker of the slider
                                  dragGestureTranslation = dragGestureTranslation > (geometry.size.width - sliderWidth - sliderPadding * 2) ? (geometry.size.width - sliderWidth - sliderPadding * 2) :  dragGestureTranslation
                                  
                                  // Set the slider value (Stepped)
                                  if steppedSlider {
                                      // Getting the stepper interval (where to place the marks)
                                      stepInterval = roundToFactor(value: dragGestureTranslation, factor: (geometry.size.width - sliderWidth - (sliderPadding * 2)) / CGFloat(step))
                                      
                                      // Get the increments for the stepepdInterval
                                      self.slider = min(max(0, Float(stepInterval)), Float(stepInterval))
                                  } else {
                                      // Set the slider value (Fluid)
                                      self.slider = min(max(0, Float(dragGestureTranslation)), Float(dragGestureTranslation))
                                  }
      
                              })
                              .onEnded({ dragValue in
                                  // Set the start marker of the slider
                                  dragGestureTranslation = dragGestureTranslation >= 0 ? dragGestureTranslation : 0
                                  
                                  // Set the end marker of the slider
                                  dragGestureTranslation = dragGestureTranslation > (geometry.size.width - sliderWidth - sliderPadding * 2) ? (geometry.size.width - sliderWidth - sliderPadding * 2) : dragGestureTranslation
                                  
                                  // Storing last drag value
                                  lastDragValue = dragGestureTranslation
                              })
                  ) // End of DragGesture
              } // End of GeometryReader
              Text("Slider: \(slider)")
          } // End of VStack
          .padding()
      }
      

      }

      【讨论】:

        猜你喜欢
        • 2020-02-05
        • 2022-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多