Reputation: 215
My App calculate for divers some important Values like max. depth etc in meter or in feet. When the User change the Slider in Metric and switch the picker to Imperial the Slider should automatically display the correctly converted result in feet. 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.
I wrote the following simple function:
import Foundation
func autoUpdateMeterToFeet(meter: Double) -> Float {
return ceil(Float(meter * 3.281))
}
The Code from the Slider:
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, value_meter: $value_meter_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
@Binding var value_meter: 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")
Text("\(autoUpdateMeterToFeet(meter: value_meter), specifier: "%.0f")")
}
}
}
}
But When I replace $value_feet in ValueMODft to autoUpdateMeterToFeet(meter: value_meter) comes the following error: "Cannot convert value of type 'Float' to expected argument type 'Binding'" What do I have to change?
Upvotes: 0
Views: 219
Reputation: 52645
You're probably doing some unnecessary work by trying to keep the two @State values of feet and meters in sync the whole time. Why not have one and dynamically convert between feet/meters when needed? My code below illustrates both that and the ability to make a custom Binding
that converts between the values:
struct ContentView: View {
@State var unitSelection = UserDefaults.standard.integer(forKey: "Picker")
@State var value_meter = 40.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)
} else {
ValueMODft2(value_meter: $value_meter)
}
}
}
}
}
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_meter: Double
var feetSliderBinding: Binding<Double> {
Binding<Double>(get: {
metersToFeet(meters: value_meter)
}, set: { newValue in
value_meter = feetToMeters(feet: newValue)
})
}
var body: some View {
VStack {
HStack {
Text(" ")
Slider(value: feetSliderBinding, in: 0...180, step: 1)
Text(" ")
}
HStack {
Text("\(metersToFeet(meters: value_meter), specifier: "%.0f")ft.")
Text("MOD")
Text("\(metersToFeet(meters: value_meter), specifier: "%.0f")")
}
}
}
}
func metersToFeet(meters: Double) -> Double {
return ceil(meters * 3.281)
}
func feetToMeters(feet: Double) -> Double {
return ceil(feet / 3.281)
}
Upvotes: 1