Reputation: 215
My App calculate for divers some important Values like max. depth etc in meter or in feet. If the user changes the slider (ValueMOD2) to metric, it should be possible for the imperial value to calculated automatically the correct value and displayed in the slider (ValueMODft2). For example: The picker is set to metric. The user changes the value to 60m MOD. Now the user changes to Imperial and the slider should automatically be on 197 (rounded up) (60 * 3.281 = 196.85). The same should happen from imperial to metric. How can I do that?
import SwiftUI
import Combine
struct ContentView: View {
@State var unitSelection = UserDefaults.standard.integer(forKey: "Picker")
@State var value_meter_initialized = 40.0
@State var value_feet_initialized = 100.0
var body: some View {
VStack {
HStack (alignment: .top) {
Spacer()
Picker("", selection: $unitSelection) {
Text("Metric").tag(0)
Text("Imperial").tag(1)
}
.pickerStyle(SegmentedPickerStyle()).padding(.horizontal, 89)
.onReceive(Just(unitSelection)) {
UserDefaults.standard.set($0, forKey: "Picker")
}
Spacer()
}
HStack {
if unitSelection == 0 {
ValueMOD2(value_meter: $value_meter_initialized)
} else {
ValueMODft2(value_feet: $value_feet_initialized)
}
}
}
}
}
struct ValueMOD2: View {
@Binding var value_meter: Double
var body: some View {
VStack {
HStack {
Text(" ")
Slider(value: $value_meter, in: 3...60, step: 1)
Text(" ")
}
HStack {
Text("\(value_meter, specifier: "%.0f")m")
Text("MOD")
}
}
}
}
struct ValueMODft2: View {
@Binding var value_feet: Double
var body: some View {
VStack {
HStack {
Text(" ")
Slider(value: $value_feet, in: 0...180, step: 10)
Text(" ")
}
HStack {
Text("\(value_feet, specifier: "%.0f")ft.")
Text("MOD")
}
}
}
}
Upvotes: 0
Views: 574
Reputation: 236420
You should use Swift generic Measurement
structure. Just set it as UnitLength
type and use it to convert the value from meter to feet. When displaying the value to the user you need to use MeasurementFormatter
and set the unitOptions to providedUnit
. So if the user set it to feet pass the feet measurement otherwise pass the meters:
extension Formatter {
static let measurement: MeasurementFormatter = {
let formatter = MeasurementFormatter()
formatter.unitOptions = .providedUnit
formatter.unitStyle = .medium
formatter.numberFormatter.maximumFractionDigits = 0
return formatter
}()
}
var value = 60.0
var meters: Measurement<UnitLength> { .init(value: value, unit: .meters) }
var feet: Measurement<UnitLength> { meters.converted(to: .feet) }
meters.value // 60
feet.value // 196.8503937007874
Formatter.measurement.string(from: meters) // "60 m"
Formatter.measurement.string(from: feet) // "197 ft"
Upvotes: 2