如何在SwiftUI中实现起始值为3英尺的范围滑块
修改Range Slider以3英尺为起始值的方案
要让你的Range Slider从3英尺(36英寸)开始,只需调整高度数值的映射逻辑并修正初始值设置,具体修改如下:
核心修改步骤
1. 新增基础起始高度常量
在HeightRangeSliderView中添加表示3英尺的英寸常量,作为高度计算的基准:
private let baseHeightInInches = 36.0 // 3英尺 = 36英寸
2. 调整高度数值计算逻辑
原来的代码将滑块位置直接映射为0-100英寸,现在改为从36英寸(3ft)开始累加,修改heightMinValue和heightMaxValue的计算:
var heightMinValue: Measurement<UnitLength> { Measurement(value: baseHeightInInches + (scaleMinValue / barWidth) * 100, unit: UnitLength.inches) } var heightMaxValue: Measurement<UnitLength> { Measurement(value: baseHeightInInches + (scaleMaxValue / barWidth) * 100, unit: UnitLength.inches) }
3. 设置初始值为3英尺对应的滑块位置
在ContentView中,将heightMinValue初始值改为0(滑块最左端,对应3ft),同时可按需调整heightMaxValue的初始位置:
@State var heightMinValue: Double = 0 // 滑块最左端,对应3英尺 @State var heightMaxValue: Double = 0.6 * Constants.Range.size // 示例:对应8英尺(3ft+60英寸)
修改后的完整代码
import SwiftUI struct ContentView: View { @State var heightMinValue: Double = 0 // 初始为滑块最左端,对应3英尺 @State var heightMaxValue: Double = 0.6 * Constants.Range.size // 初始对应8英尺(3ft+60英寸) var body: some View { VStack { HeightRangeSliderView(scaleMinValue: $heightMinValue, scaleMaxValue: $heightMaxValue, minimumpercentageVal: 0, lableWidth: 89) } .padding() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } struct HeightRangeSliderView: View { /// Slider绑定的最小/最大值 @Binding var scaleMinValue: Double @Binding var scaleMaxValue: Double var minimumpercentageVal: Double var leftKnobWidth: Double = 28 var leftKnobHeight: Double = 28 var rightKnobWidth: Double = 28 var rightKnobHeight: Double = 28 var barWidth: Double = Constants.Range.size var leftKnobColor = Color.white var rightKnobColor = Color.white var backgroundTrackColor = Color.DesignSystem.Divider var selectedTrackColor = Color.DesignSystem.Active /// 滑块最小/最大值标签颜色 var sliderMinMaxValuesColor = Color.DesignSystem.Active /// 滑块标签尺寸 var lableWidth: Double = 55 var lableColor = Color.DesignSystem.FieldBg // 基础起始高度:3英尺 = 36英寸 private let baseHeightInInches = 36.0 private let heightformatStyle = Measurement<UnitLength>.FormatStyle(width: .abbreviated, usage: .personHeight) var heightMinValue: Measurement<UnitLength> { Measurement(value: baseHeightInInches + (scaleMinValue / barWidth) * 100, unit: UnitLength.inches) } var heightMaxValue: Measurement<UnitLength> { Measurement(value: baseHeightInInches + (scaleMaxValue / barWidth) * 100, unit: UnitLength.inches) } var body: some View { VStack { /// 滑块当前最小/最大值显示 HStack { Text(heightMinValue, format: heightformatStyle) .monospacedDigit() .frame(width: lableWidth, height: 40, alignment: .center) .foregroundColor(sliderMinMaxValuesColor) .background(lableColor, in: RoundedRectangle(cornerRadius: 8)) Spacer() Text(heightMaxValue, format: heightformatStyle) .monospacedDigit() .frame(width: lableWidth, height: 40, alignment: .center) .foregroundColor(sliderMinMaxValuesColor) .background(lableColor, in: RoundedRectangle(cornerRadius: 8)) } .frame(width: (barWidth + (rightKnobWidth * 2))) .padding(.horizontal) /// 滑块轨道视图 ZStack(alignment: .leading) { // 背景轨道 Capsule() .fill(backgroundTrackColor) .frame(width: (barWidth + (rightKnobWidth * 2)), height: 6) // 选中的轨道 Capsule() .fill(selectedTrackColor) .frame(width: scaleMaxValue - scaleMinValue, height: 6) .offset(x: scaleMinValue + rightKnobWidth) HStack(spacing: 0) { // 左旋钮 Circle() .fill(leftKnobColor) .shadow(color: Color.black.opacity(0.2), radius: 12, x: 0, y: 6) .shadow(color: Color.black.opacity(0.2), radius: 4, x: 0, y: 0.5) .frame(width: leftKnobWidth, height: leftKnobHeight) .offset(x: scaleMinValue) .gesture(DragGesture().onChanged({ value in // 拖拽边界限制:左旋钮不能超过右旋钮,且不能小于0 if value.location.x >= 0 && value.location.x <= scaleMaxValue { scaleMinValue = value.location.x } })) // 右旋钮 Circle() .fill(rightKnobColor) .shadow(color: Color.black.opacity(0.2), radius: 12, x: 0, y: 6) .shadow(color: Color.black.opacity(0.2), radius: 4, x: 0, y: 0.5) .frame(width: rightKnobWidth, height: rightKnobHeight) .offset(x: scaleMaxValue) .gesture(DragGesture().onChanged({ value in // 拖拽边界限制:右旋钮不能超过轨道长度,且不能小于左旋钮 if value.location.x <= barWidth && value.location.x >= scaleMinValue { scaleMaxValue = value.location.x } })) } } } } } enum Constants { enum Range { static let size = UIScreen.main.bounds.width - 100 } } extension Color { enum DesignSystem { public static let Active = Color.green public static let FieldBg = Color.black public static let Divider = Color.gray } }
效果说明
修改后:
- 滑块左旋钮最左端对应3英尺(3ft),完全符合需求
- 滑块位置比例将转换为从3ft开始的高度(比如滑块拉到中间时,显示3ft+50英寸=7ft2)
- 拖拽逻辑保持原有边界限制,确保左旋钮不会超过右旋钮,右旋钮不会超出轨道范围
内容的提问来源于stack exchange,提问作者byaruhaf
相关产品推荐
相关产品推荐

