-1

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.
enter image description here

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.

Bashir
  • 2,057
  • 5
  • 19
  • 44
Mr Android
  • 37
  • 5
  • What's the problem you're having? – cactustictacs Dec 16 '20 at 15:40
  • Hi. I've seen tutorials and sample code demonstrating a time picker(spinner), counting in 5, 10 15. My time picker works fine if i assign 5 for intervals of 5 minutes. But I want intervals of 30 min. You see in the picture above, when I assign interval of 30, it only shows 0, 30, and stops counting. This is something I want to fix. – Mr Android Dec 16 '20 at 15:52
  • @MrAndroid The counter is designed to go up until 60. Your output goes up until 60. What's the issue? – Aplet123 Dec 16 '20 at 16:22
  • I'm sorry if I sound stupid now, please forgive me, but okay I know what you are saying. I just don't know how to get it to default to 00 and keep going like, 00, 30, 60 and repeat. At first glance it seemed simple to me, but I tried altering the code and keep failing. – Mr Android Dec 16 '20 at 16:27
  • Just change the bound in `i < 60` to a larger number. – Aplet123 Dec 16 '20 at 16:29
  • Sorry what I meant was after the 30, there should be 00 again instead of just blank. That or once I reach 00, the whole number should change. For example. If it's at 12;30 and I scroll downward to 00, then 12:30 should become 13:00 automatically. – Mr Android Dec 16 '20 at 17:10

1 Answers1

0

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 NumberPickers 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

cactustictacs
  • 17,935
  • 2
  • 14
  • 25