I'm using a time picker spinner. I would like to implement 30 min intervals.
The code I'm using outputs this effect as shown in the below image.
Here's the code:
picker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
@Override
public void onTimeChanged(TimePicker view, int hour, int min) {
timeoutput.setText(String.format("%02dh%02d", hour, min));
}
});
back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Schedule.this, choosewalk.class);
startActivity(intent);
}
});
@SuppressLint("DefaultLocale")
private void TimeInterval(TimePicker picker) {
try {
int Interval = 30;
NumberPicker minute = (NumberPicker) picker.findViewById(Resources.getSystem().getIdentifier(
"minute", "id", "android"));
minute.setMinValue(0);
minute.setMaxValue((60 / Interval) - 1);
List<String> displayedValue = new ArrayList<String>();
for (int i = 0; i < 60; i += Interval) {
displayedValue.add(String.format("%02d", i));
}
minute.setDisplayedValues(displayedValue.toArray(new String[0]));
} catch (Exception e) {
e.printStackTrace();
}
}
I know that that there are similar questions, but for this specific problem, I'm struggling. I know the method works for intervals of 5, 10, 15, etc. It's altering the code for 30 min intervals that's problematic.
Ok, here's your problem. You want a wheel with 00
and 30
on it, and you want to be able to infinitely scroll it, so it ticks over from 30
to 00
and increments the hour wheel each time, right? Which is basically how the TimePicker
works by default.
The issue is this, from NumberPicker
:
Note: If the number of items, i.e. the range (
getMaxValue()
-getMinValue()
) is less than the number of items shown on the selector wheel, the selector wheel will not wrap.
the max - min thing is an extremely awkward way of expressing this (the number of items is actually that + 1) - but basically the spinner shows three items on-screen at a time, and you need to have more than three items (so at least one is off-screen) for wrapping to work. That's why is works for your other intervals (15 mins gives you four items, so that wraps)
Unfortunately I don't think there's a lot you can do about it - the lack of wrapping is hardcoded behaviour in NumberPicker
. You could fake it by having four items, 00
, 30
, 00
, 30
but internally that's still values 0
to 3
, one rotation of the wheel, not two. And the TimePicker
uses those values, comparing to minValue
and maxValue
to check when the wheel has wrapped and the hour needs to automatically change.
The listener that handles this (in TimePickerSpinnerDelegate
) can't be read, so you can't wrap it in a listener that pretends it's going 0
1
0
1
instead. The listener also refers to a bunch of internal private variables and methods, so you can't just copy it into your own code and make the tweaks. You'd have to reimplement the whole widget and its related classes by the looks of things
If it works for you, you could just throw two NumberPicker
s together and remake it yourself. You'll lose things like the AM/PM functionality, probably accessibility, it depends if you care or not. This basically works:
public class MainActivity extends AppCompatActivity implements NumberPicker.OnValueChangeListener {
private NumberPicker mMinuteSpinner;
private NumberPicker mHourSpinner;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMinuteSpinner = findViewById(R.id.minPicker);
mHourSpinner = findViewById(R.id.hourPicker);
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(3);
mMinuteSpinner.setDisplayedValues(new String[]{"00", "30", "00", "30"});
mMinuteSpinner.setOnValueChangedListener(this);
mHourSpinner.setMinValue(0);
mHourSpinner.setMaxValue(23);
String[] hours = new String[24];
for (int i = 0; i < 24; i++) {
hours[i] = Integer.toString(i + 1);
}
mHourSpinner.setDisplayedValues(hours);
}
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean advanced = (newVal == 0 && oldVal == 3) || (newVal == 2 && oldVal == 1);
boolean regressed = (newVal == 3 && oldVal == 0) || (newVal == 1 && oldVal == 2);
if (advanced) {
mHourSpinner.setValue(mHourSpinner.getValue() + 1);
} else if (regressed) {
mHourSpinner.setValue(mHourSpinner.getValue() - 1);
}
}
}
Haven't touched Java in a while! There might be a better way to do that. But yeah, the listener is just checking to see if it's passing between the two rollover points on the four-item list (where it goes from 30
to 00
scrolling one way, or vice versa scrolling the other way). This is basically how the TimePicker
works