I've created a view for setting a time (minutes and seconds). It uses two wheel pickers bound to two state variables.
Now I'd like to use that view at different places in the app, but I don't like the interface with two seperate variables for the time. Instead, I'd like to have just one bound variable holding the time in seconds (so time = 185 would translate to 3 minutes and 5 seconds).
Is it possible to have some sort of "adapter" between bindings?
Here's the view:
import SwiftUI
struct TimePicker: View {
    var minutes: Binding<Int>
    var seconds: Binding<Int>
    var body: some View {
        HStack() {
            Spacer()
            Picker(selection: minutes, label: EmptyView()) {
                ForEach((0...9), id: \.self) { ix in
                    Text("\(ix)").tag(ix)
                }
                }.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
            Text("Min.")
            Picker(selection: seconds, label: EmptyView()) {
                ForEach((0...59), id: \.self) { ix in
                    Text("\(ix)").tag(ix)
                }
                }.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
            Text("Sec.")
            Spacer()
        }
    }
}
Here is the approach based on the Binding(get:set:)
struct TimePicker: View {
    @Binding var total: Int
    
    var minutes: Binding<Int> {
        Binding<Int>(get: { self._total.wrappedValue / 60 },
                     set: { self._total.wrappedValue = self._total.wrappedValue % 60 + $0 * 60 })
    }
    var seconds: Binding<Int> {
        Binding<Int>(get: { self._total.wrappedValue % 60 },
                     set: { self._total.wrappedValue = (self._total.wrappedValue / 60) * 60 + $0 })
    }
    
    var body: some View {
        HStack() {
            Spacer()
            Picker(selection: minutes, label: EmptyView()) {
                ForEach((0...9), id: \.self) { ix in
                    Text("\(ix)").tag(ix)
                }
            }.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
            Text("Min.")
            Picker(selection: seconds, label: EmptyView()) {
                ForEach((0...59), id: \.self) { ix in
                    Text("\(ix)").tag(ix)
                }
                }.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
            Text("Sec.")
            Spacer()
        }.frame(height: 200)
    }
}
struct TestTimePicker: View {
    
    @State var seconds = 185
    var body: some View {
        VStack {
            Text("Current: \(seconds)")
            TimePicker(total: $seconds)
        }
    }
    
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With