我正在制作一些使用流体体积的东西,并希望使其适用于使用英制和公制的用户。
我目前在滑块上将公制转换为英制时遇到问题,
ClosedRange
最大化到错误的值。
我不完全确定我哪里出了问题,但也不知道这是否是处理问题的最佳方法。
我的思考过程是将所有内容都以公制存储,并为那些希望为他们转换英制 UI 的用户 - 因为公制是我的主要测量单位(并且对我来说更容易阅读)。
这是我正在使用的测试代码:
struct SettingsMenu: View {
private let types: [UnitVolume] = [.milliliters, .fluidOunces]
@State private var selectedUnitVolume: UnitVolume = .milliliters
@State private var selectedGoal: Double = 2000
var body: some View {
Form {
Section {
Picker("Measurement unit", selection: $selectedUnitVolume) {
ForEach(types, id: \.self) { type in
Text(type.symbol).tag(type)
}
}
.onChange(of: selectedUnitVolume) { _, newUnit in
if newUnit == .milliliters {
selectedGoal = Measurement(value: selectedGoal, unit: UnitVolume.fluidOunces).converted(to: .milliliters).value
} else {
selectedGoal = Measurement(value: selectedGoal, unit: UnitVolume.milliliters).converted(to: .fluidOunces).value
}
}
VStack(alignment: .leading) {
Label(label, systemImage: "drop.fill")
Slider(value: $selectedGoal, in: range, step: step) {
Text("Drink goal")
} minimumValueLabel: {
Text("\(Int(range.lowerBound))")
.font(.footnote)
.foregroundStyle(.gray)
} maximumValueLabel: {
Text("\(Int(range.upperBound))")
.font(.footnote)
.foregroundStyle(.gray)
}
}
}
}
}
var range: ClosedRange<Double> {
selectedUnitVolume == .milliliters ? 100...5000 : 3...175
}
var step: Double {
selectedUnitVolume == .milliliters ? 50 : 1
}
var label: String {
let value = selectedUnitVolume == .milliliters ? selectedGoal : Measurement(value: selectedGoal, unit: UnitVolume.milliliters).converted(to: .fluidOunces).value.rounded()
return "Daily saving goal: \(value.formatted(.number)) \(selectedUnitVolume.symbol)"
}
}
结果如下:
如您所见,设备中的开关确实更新了滑块最小/最大的标签,但实际范围和
label
不正确。
你的代码的主要逻辑是好的。但这里有两个问题。
您正在将显示的标签值转换两次。去掉标签函数中的转换
var label: String {
return "Daily saving goal: \(selectedGoal.formatted(.number)) \(selectedUnitVolume.symbol)"
}
您返回的毫升或液量盎司范围是错误的。 100 毫升不是 3 盎司,而是 33.81 盎司。上限为 169.07。