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