我正在制作使用流体音量的东西,并想让它同时适用于使用英制和公制的用户.

我目前在将滑块上的公制转换为英制时遇到了问题,ClosedRange的最大值是错误的.

我不完全确定我错在哪里,但我也不确定这是否是处理它的最好方法.

我的 idea 是将一切都存储在公制中,对于那些想要为他们转换用户界面的用户来说--因为公制是我的主要衡量标准(对我来说更容易阅读).

这是我使用的测试代码:

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)"
  }
}

这导致了以下结果:

iOS app with slider switching between metric millilitres and imperial fluid ounce, but the conversion in the UI is incorrect

如您所见,单元中的switch 确实更新了滑块的最小/最大值标签,但实际范围和label是不正确的.

推荐答案

您的代码的主要逻辑是正确的.但这里有两个问题.

  • 您正在转换显示的标签值两次.移除LABEL函数中的转换

    var label: String {
        return "Daily saving goal: \(selectedGoal.formatted(.number)) \(selectedUnitVolume.symbol)"
    }
    
  • 您返回的ml或fl oz范围是错误的.上限为169.07.

我建议您在更改单位时对值进行四舍五入,以便更好地适应您给出的步长范围.

Swift相关问答推荐

计算Vision OS相机与Vision OS中3D模型之间的距离

绑定到可选值的非可选属性?'

如何在每天午夜重置布尔值

如何使用AsyncTimerSequence获取初始时钟,然后在指定的时间间隔内开始迭代?

在NavigationStack上设置拐角半径:SwiftUI中的无响应内容视图区

在一行语句中比较Date.now的相等性是否安全

将变量设置为 @Published 会 destruct 代码而不会出现任何错误

BLE 在 ESP32 和 Iphone 之间发送字符串

如何在设备(或常量)地址空间中创建缓冲区?

为什么这段Swift读写锁代码会导致死锁?

如何使一个 Reality Composer 场景中的分组对象可拖动?

SwiftUI Preview 不适用于 Core Data

无法分配给属性:absoluteString是一个只能获取的属性

如何使用 swift 将 Images.xcassets 中的图像加载到 UIImage 中

用 UIBezierPath 画一条线

Swift performSegueWithIdentifier 不起作用

如何将应用程序与 iOS 联系人应用程序集成?

从 Swift 初始化程序调用方法

如何在 Swift 中从字符串创建类的实例

iPhone 纵向和 iPad 横向的通用应用程序