lula08
lula08

Reputation: 215

SwiftUI: How can I automatically calculate from metric to imperial?

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

Answers (1)

Leo Dabus
Leo Dabus

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

Related Questions