Home > OS >  SwiftUI picker value to reset if it goes beyond max
SwiftUI picker value to reset if it goes beyond max

Time:08-01

I have a custom SwiftUI picker. The picker takes two things: hour and minute. My struct has a value called maxDurationSeconds. My goal is, if the user selects a combination of hour and minute, which makes the overall go above the maxDurationSeconds, I want to reset both hour and minute to zero.

var body: some View {
    let hours = [Int](0...maxHours)
    let minutes = [Int](0...maxMinutes)
    GeometryReader { geometry in
        HStack(spacing: 0) {
            Picker(selection: self.selection.hours, label: Text("")) {
                ForEach(0..<maxHours, id: \.self) { index in
                    Text("\(hours[index]) hr")
                        .foregroundColor(Color(Asset.Color.V2.white.color))
                }
            }
            .pickerStyle(.wheel)
            .frame(width: geometry.size.width / 2, height: geometry.size.height, alignment: .center)
            Picker(selection: self.selection.minutes, label: Text("")) {
                ForEach(0..<maxMinutes, id: \.self) { index in
                    Text("\(minutes[index]) min")
                        .foregroundColor(Color(Asset.Color.V2.white.color))
                }
            }
            .pickerStyle(.wheel)
            .frame(width: geometry.size.width / 2, height: geometry.size.height, alignment: .center)
        }
    }
}

The rest of the struct is omitted since the file is huge. But here is the necessary info: We are getting a binding from selection, which has hour and minute in it. MaxHours and maxMinutes are 24 and 60.

This is what I am trying to achieve:

    let hoursInSeconds = selection.hours.wrappedValue
    let minutesInSeconds = selection.minutes.wrappedValue
    if(hoursInSeconds   minutesInSeconds > Int(maxDurationSeconds)) {
        selection.hours.wrappedValue = 0
        selection.minutes.wrappedValue = 0
    }

I am not sure where to include this code. I tried doing on tap gesture of the picker views and doing this, but it would not update them. Any feedback is greatly appreciated.

CodePudding user response:

It can be done on change of selection, like

GeometryReader { geometry in
    HStack(spacing: 0) {
      // ... content 
    }
    .onChange(of: selection) { _ in // << assuming you confirm it to Equatable
   // .onChange(of: [selection.hours, selection.minutes]) { _ in // << alternate
         if(selection.hours   selection.minutes > Int(maxDurationSeconds)) {
           selection.hours = 0
           selection.minutes = 0
        }
    }
}
  • Related