Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to translate bindings in a view?

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()
        }
    }
}
like image 807
G. Marc Avatar asked Oct 27 '25 08:10

G. Marc


1 Answers

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)
        }
    }
    
}
like image 127
Asperi Avatar answered Oct 30 '25 12:10

Asperi