Show TimePicker with minutes intervals in android

71,354

Solution 1

Use the following the custom class called CustomTimePickerDialog, which I think solve your problem.

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.widget.NumberPicker;
import android.widget.TimePicker;

public class CustomTimePickerDialog extends TimePickerDialog {

    private final static int TIME_PICKER_INTERVAL = 5;
    private TimePicker mTimePicker;
    private final OnTimeSetListener mTimeSetListener;

    public CustomTimePickerDialog(Context context, OnTimeSetListener listener,
            int hourOfDay, int minute, boolean is24HourView) {
        super(context, TimePickerDialog.THEME_HOLO_LIGHT, null, hourOfDay,
                minute / TIME_PICKER_INTERVAL, is24HourView);
        mTimeSetListener = listener;
    }

    @Override
    public void updateTime(int hourOfDay, int minuteOfHour) {
        mTimePicker.setCurrentHour(hourOfDay);
        mTimePicker.setCurrentMinute(minuteOfHour / TIME_PICKER_INTERVAL);
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        switch (which) {
            case BUTTON_POSITIVE:
                if (mTimeSetListener != null) {
                    mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
                            mTimePicker.getCurrentMinute() * TIME_PICKER_INTERVAL);
                }
                break;
            case BUTTON_NEGATIVE:
                cancel();
                break;
        }
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        try {
            Class<?> classForid = Class.forName("com.android.internal.R$id");
            Field timePickerField = classForid.getField("timePicker");
            mTimePicker = (TimePicker) findViewById(timePickerField.getInt(null));
            Field field = classForid.getField("minute");

            NumberPicker minuteSpinner = (NumberPicker) mTimePicker
                .findViewById(field.getInt(null));
            minuteSpinner.setMinValue(0);
            minuteSpinner.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
            List<String> displayedValues = new ArrayList<>();
            for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
                displayedValues.add(String.format("%02d", i));
            }
            minuteSpinner.setDisplayedValues(displayedValues
                    .toArray(new String[displayedValues.size()]));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Here is the demonstrating screenshot.

enter image description here

Solution 2

There is this awesome library MaterialDateTimePicker that creates beautiful styled material timepickers.

You can use one of the following methods to define your interval:

  • setSelectableTimes(Timepoint[] times) You can pass in an array of Timepoints. These values are the only valid selections in the picker. setMinTime(Timepoint time) and setMaxTime(Timepoint time) will further trim this list down.

  • setTimeInterval(int hourInterval, int minuteInterval, int secondInterval) Set the interval for selectable times in the TimePickerDialog. This is a convenience wrapper around setSelectableTimes

Solution 3

/**
 * Set TimePicker interval by adding a custom minutes list
 *
 * @param timePicker
 */
private void setTimePickerInterval(TimePicker timePicker) {
    try {

        NumberPicker minutePicker = (NumberPicker) timePicker.findViewById(Resources.getSystem().getIdentifier(
                "minute", "id", "android"));
        minutePicker.setMinValue(0);
        minutePicker.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
        List<String> displayedValues = new ArrayList<String>();
        for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
            displayedValues.add(String.format("%02d", i));
        }
        minutePicker.setDisplayedValues(displayedValues.toArray(new String[0]));
    } catch (Exception e) {
        Log.e(TAG, "Exception: " + e);
    }
}

Solution 4

As @anddev84 said, you can do it with your own customized TimePickerDialog.

However, take a look of the source code you can find:

  1. TimePickerDialog is a frame layout, see this file. And it just contains a TimePicker
  2. The TimePicker widget is just a linear layout, see this file. And you can see the minute spinner is a NumberPicker
  3. Refer to the code of NumberPicker, you will find it has a public method setDisplayedValues(String[] displayedValues)

    /**
     * Sets the values to be displayed.
     *
     * @param displayedValues The displayed values.
     */
    public void setDisplayedValues(String[] displayedValues)
    

So, with these information, I suppose you can simply customize your own time picker dialog with limited minutes displayed.

Solution 5

Struggled with 30 min interval more then hour. Might struggle more if wouldn't see the comment of @Lee. So just post a full code of dialog with 30 min interval:

public class IntervalTimePickerDialog extends TimePickerDialog {
    private static final String TAG = "IntervalPickerDialog";

    private final static int TIME_PICKER_INTERVAL = 30;
    private TimePicker timePicker;
    private final OnTimeSetListener callback;

    private int lastHour = -1;
    private int lastMinute = -1;

    public IntervalTimePickerDialog(Context context, int themeId, OnTimeSetListener callBack,
                                    int hourOfDay, int minute, boolean is24HourView) {
        super(context, themeId, callBack, hourOfDay, minute / TIME_PICKER_INTERVAL,
                is24HourView);
        lastHour = hourOfDay;
        lastMinute = minute;
        this.callback = callBack;
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (callback != null && timePicker != null) {
            timePicker.clearFocus();
            callback.onTimeSet(timePicker, timePicker.getCurrentHour(),
                    timePicker.getCurrentMinute() * TIME_PICKER_INTERVAL);
        }
    }

    @Override
    protected void onStop() {
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        try {
            Class<?> classForid = Class.forName("com.android.internal.R$id");
            Field timePickerField = classForid.getField("timePicker");
            this.timePicker = (TimePicker) findViewById(timePickerField.getInt(null));
            Field field = classForid.getField("minute");

            NumberPicker mMinuteSpinner = (NumberPicker) timePicker.findViewById(field.getInt(null));
            mMinuteSpinner.setMinValue(0);
            mMinuteSpinner.setMaxValue((60 / TIME_PICKER_INTERVAL) - 1);
            List<String> displayedValues = new ArrayList<>();
            for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
                displayedValues.add(String.format("%02d", i));
            }
            mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0]));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        super.onTimeChanged(view, hourOfDay, minute);
        if (lastHour != hourOfDay && lastMinute != minute) {
            view.setCurrentHour(lastHour);
            lastMinute = minute;
        } else {
            lastHour = hourOfDay;
            lastMinute = minute;
        }
    }
Share:
71,354
Sergio76
Author by

Sergio76

Updated on July 09, 2022

Comments

  • Sergio76
    Sergio76 almost 2 years

    My application show a TimePickerDialog to set a time. I want that the timePickerDialog show the minutes with an interval of 5 minutes.

    This works fine with this code:

    private final int TIME_PICKER_INTERVAL=5;
    private boolean mIgnoreEvent=false;
    …
        public TimePickerDialogs(Context arg0, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) {
        super(arg0, callBack, hourOfDay, minute, is24HourView);
    
        formato=Statics.formato;
    }
    
    @Override
    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        //super.onTimeChanged(arg0, arg1, arg2);
    
        if (mIgnoreEvent)
            return;
        if (minute%TIME_PICKER_INTERVAL!=0){
            int minuteFloor=minute-(minute%TIME_PICKER_INTERVAL);
            minute=minuteFloor + (minute==minuteFloor+1 ? TIME_PICKER_INTERVAL : 0);
            if (minute==60)
                minute=0;
            mIgnoreEvent=true;
            view.setCurrentMinute(minute);
            mIgnoreEvent=false;
        }
    }
    

    Although only minutes can be selected with an interval of five minutes, the timepickerdialog looks like:

    hours and minutes

    do not know how the minutes also show the range of 5 minutes, as in this picture:

    hours and minutes - 5

    I have searched but can not find the solution.

  • Rajiv yadav
    Rajiv yadav over 10 years
    NumberPicker is not available in pre honeycomb. Suggest me some solution for that
  • arlomedia
    arlomedia almost 10 years
    This worked perfectly for me, thank you! I modified the constructor to take an interval argument and replaced the TIME_PICKER_INTERVAL constant with an interval variable ... but realistically I don't expect to ever need an interval other than 5.
  • Lee Yi Hong
    Lee Yi Hong almost 10 years
    I works ok for 15 minutes interval but not on 30 minutes interval
  • Lee Yi Hong
    Lee Yi Hong almost 10 years
    Ok, I manage to solve the 30 minutes interval by adding a onTimeChanged check with last save hours and minutes. If both are different, it will only change the minutes instead of both of them by using view.setCurrentHour(lastSavedHour). I am not sure if this is a good way of doing it... But if there are better solution do feel free to let me know :)
  • otgw
    otgw over 9 years
    I feel the need to clarify @LeeYiHong's comment because I was confused until I implemented it. It works. It just has an annoying bug. For example if you change from 14:00 to :30, the hour goes back to 13.
  • Leon Lucardie
    Leon Lucardie over 9 years
    This piece of code doesn't work for the Android 5.0 version of the TimePickerDialog, since it doesn't use the NumberPicker widget for minute selection.
  • Ryan C
    Ryan C about 9 years
    @LeonLucardie if you change the super call to be super(context, TimePickerDialog.THEME_HOLO_LIGHT, callBack, hourOfDay, minute, is24HourView); it will work with Android 5.0. Passing the theme makes it use the picker style timeDialog. I've submitted an edit to the answer.
  • Stornu2
    Stornu2 about 9 years
    THANKS!! you are a genius
  • Khay
    Khay about 9 years
    @LeonLucardie - this pice of code will work fine if you change your CustomTimePicker style in xml from clock to Analog . Although even i'm in need to find out which widget does time picker in clock style uses ? any idea anyone?
  • gellezzz
    gellezzz almost 9 years
    Your TimePicker class have error: NumberPicker mMinuteSpinner = (NumberPicker) mMinuteSpinner.setMinValue(0);
  • MJim
    MJim almost 9 years
    Ups, you are right. I forgot a code line. Bug solved now. Thanks!
  • Fearghal
    Fearghal almost 9 years
    Hi - how do I init this class on th UI - do i init a it using a timepicker component eg CustomTimePickerDialog ctp = ...findViewById(R.id.timePicker); ?
  • Fearghal
    Fearghal almost 9 years
    How does this get attached to the UI, do i need a Time picker on in my xml layout?
  • MJim
    MJim almost 9 years
    You don't need any TimePicker in your xml layout. Just place a LinearLayout element at the position the TimePicker would be and let the Activity populate it as shown above.
  • John Sardinha
    John Sardinha about 8 years
    does that lib work on a fragment with another views in it, or just as a dialog?
  • Jeff Lockhart
    Jeff Lockhart almost 8 years
    This code works great, except there's one flaw. If updateTime() is called, the minutes are not normalized by dividing by TIME_PICKER_INTERVAL before setting the minutes value on the TimePicker.
  • Jeff Lockhart
    Jeff Lockhart almost 8 years
    Also, the implementation of onClick() has changed in the most recent versions of the API to handle BUTTON_NEGATIVE. I'll update the answer to reflect these changes.
  • Jeff Lockhart
    Jeff Lockhart almost 8 years
    This code also, inexplicably, doesn't work in 7.0 Nougat. The source code would seem it's mostly unchanged from 6.0.1 Marshmallow in terms of how it handles the TimePickerMode in the theme to choose between TimePickerSpinnerDelegate and TimePickerClockDelegate. But despite the mode being set to "spinner", on API 24 the clock layout is always used. This is an issue with the stock android.app.TimePickerDialog though.
  • Jeff Lockhart
    Jeff Lockhart almost 8 years
    I created an issue in the Android bug tracker: code.google.com/p/android/issues/detail?id=222208
  • Jeff Lockhart
    Jeff Lockhart almost 8 years
    I've written some workaround code for this issue with Nougat only displaying the clock. I can share if anyone else is experiencing the same problem.
  • Ghanshyam Nayma
    Ghanshyam Nayma over 7 years
    can any one help me how to call this class. bcz simply I am calling this constructor and calling method dialog.show(). But getting exception android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
  • Ghanshyam Nayma
    Ghanshyam Nayma over 7 years
    can any one help me how to call this class. bcz simply I am calling this constructor and calling method dialog.show(). But getting exception android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
  • Rajath
    Rajath over 7 years
    @JohnSardinha, it's a dialog based on the corresponding Android api, but needs an instance of the FragmentManager for it's show() function.
  • André Luiz Reis
    André Luiz Reis almost 6 years
    This library works for me. Solved my problem. I can set intervals of 30 minutes, for example.
  • Daniel Wilson
    Daniel Wilson over 5 years
    I feel this will break in the future - Google is clamping down on accessing internals with reflection :(
  • Dan
    Dan over 5 years
    can this lib be customized to use spinner instead of clock? Most solutions I have seen seem to use reflection and they do not work on all android versions.
  • user1510006
    user1510006 almost 5 years
    team, I am getting this error, any help please. java.lang.NoSuchFieldException: TimePicker with Android 9 .
  • user1510006
    user1510006 almost 5 years
    @ Adrián Rivero : java.lang.NoSuchFieldException: TimePicker with Android 9 . I am getting this error, any help please.
  • user1510006
    user1510006 almost 5 years
    @ Yevhenii Kanivets , getting this error for Android 9 , any help please . java.lang.NoSuchFieldException: TimePicker
  • Yev Kanivets
    Yev Kanivets almost 5 years
    @user1510006 they've just changed the name of field to smth another (don't know which is the new name). This is exactly why reflection is the bad solution.
  • user1510006
    user1510006 almost 5 years
    @Yevhenii Kanivets , thank you for your reply, so, do we have another solution to keep the spinner UI ?
  • Riddhi Shah
    Riddhi Shah almost 5 years
    how can we achieve this in Clock Mode?
  • darkrider1287
    darkrider1287 over 4 years
    beware that when retrieving the resulting time via an OnTimeChangedListener, the resulting "minute" var transmitted is INCORRECT, and will be equal to "minute selected / interval". for example, using an interval of 5 minutes, selecting 6:15 on the UI will yield an OnTimeChangedListener minute var of 3. 6:30 yields minute=6, etc.
  • Oluwasegun Wahaab
    Oluwasegun Wahaab over 4 years
    @RiddhiShah, this can be done in clock mode. Just omit the attribute TimePickerDialog.THEME_HOLO_LIGHT from the constructor and this makes the timepicker default to clock mode. your new call to super will be something like super(context, null, hourOfDay, minute / TIME_PICKER_INTERVAL, is24HourView);
  • Suresh Maidaragi
    Suresh Maidaragi almost 4 years
    @user1510006 try removing the line ` throw new RuntimeException(e);` from catch block this will work
  • arlomedia
    arlomedia over 2 years
    With compileSdkVersion 30 and Android 11, getting the minuteSpinner in onAttachedToWindow works differently: mTimePicker = findViewById(Resources.getSystem().getIdentifier("timePicker‌​", "id", "android")), then val minuteSpinner = mTimePicker?.findViewById<NumberPicker>(Resources.getSystem(‌​).getIdentifier("min‌​ute", "id", "android")) (Kotlin)
  • ahmed saber
    ahmed saber about 2 years
    i have a problem when i make interval 30 For example if you change from 14:00 to :30, the hour goes back to 13.