Android - TimePicker minutes to 15
Asked Answered
T

12

40

Can I control the Android TimePicker view to just show the minutes to 15 minutes interval?

Meaning if it's 12:28 now, show 12:30 and clicking the + and - button will increment and decrement by 15?

Tetrachord answered 5/4, 2010 at 18:28 Comment(0)
B
22

Create a xml file and name it activity_time_picker.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

 <TimePicker
        android:id="@+id/timePicker1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/layoutHourMinute"
        android:layout_centerInParent="true"

        />

</RelativeLayout>

now create activity class like this

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

import android.annotation.SuppressLint;

import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.NumberPicker;
import android.widget.TimePicker;

public class TimePickerActivity extends Activity {


    TimePicker timePicker;
    private int TIME_PICKER_INTERVAL = 15;
     NumberPicker minutePicker;
     List<String> displayedValues;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
                 super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setContentView(R.layout.activity_time_picker);
        super.onCreate(savedInstanceState);
        timePicker = (TimePicker)findViewById(R.id.timePicker1);

        timePicker.setIs24HourView(true);
        timePicker.setCurrentHour(0);
        timePicker.setCurrentMinute(0);

        setTimePickerInterval(timePicker);
    }
@SuppressLint("NewApi")
    private void setTimePickerInterval(TimePicker timePicker) {
         try {
                Class<?> classForid = Class.forName("com.android.internal.R$id");
               // Field timePickerField = classForid.getField("timePicker");  

                Field field = classForid.getField("minute");
                minutePicker = (NumberPicker) timePicker
                        .findViewById(field.getInt(null));

                minutePicker.setMinValue(0);
                minutePicker.setMaxValue(3);
                displayedValues = new ArrayList<String>();
                for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
                    displayedValues.add(String.format("%02d", i));
                }
              //  for (int i = 0; i < 60; i += TIME_PICKER_INTERVAL) {
              //      displayedValues.add(String.format("%02d", i));
              //  }
                minutePicker.setDisplayedValues(displayedValues
                        .toArray(new String[0]));
               minutePicker.setWrapSelectorWheel(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
    }
}
Buttock answered 9/4, 2014 at 9:44 Comment(14)
The hour doesn't change when moving between 45 and 00. I changes after two repetitions only...Naxos
@Naxos you are right. It is a bug. Actually I added minute two times. Without doing so it was not able to auto scroll minutes. I will try to fix it and update my answer as I get it fixed.Buttock
I wish I can apply this solution but Android Studio complain ClassNotFoundException on Class.forName("com.android.internal.R$id") even if android.jar already exist in the External Libraries.Guido
This solution worked for me. Quick note: I had to customize the getCurrentMinute() and setCurrentMinute() methods.Amphichroic
Hi, I am facing new issue, display time is ok with difference of 5 or 15 mins but while getting minutes shows original timeAmidst
@Amidst you can get minutes in public void onTimeChanged(TimePicker view, int hourOfDay, int minute) method like this int min= Integer.parseInt(displayedValues.get(minutePicker.getValue()));Buttock
hi, could you explain what exactly com.android.internal.R$id stands for?Damnable
@Damnable you can see explanation here devmaze.wordpress.com/2011/01/18/…Buttock
@Buttock : please can you explain why : minutePicker.setMaxValue(7); ?Nazarene
@Buttock : i did not understand where does the 7 come from ?Nazarene
/** * Sets the max value of the picker. * * @param maxValue The max value inclusive. * * Note: The length of the displayed values array * set via {@link #setDisplayedValues(String[])} must be equal to the * range of selectable numbers which is equal to * {@link #getMaxValue()} - {@link #getMinValue()} + 1. */ public void setMaxValue(int maxValue)Buttock
@Buttock very good approach, but it's too good if it also support API 9 and aboveLint
Do refer to #33597619, there is actually not a need to added minute two timesRaddy
@yeeen, thanks for providing good information. This is the way community get benefited. I have edited my answer accordingly.Buttock
I
21

Here's my version where you can set the interval:

private static final int TIME_PICKER_INTERVAL=15;
private boolean mIgnoreEvent=false;

private TimePicker.OnTimeChangedListener mTimePickerListener=new TimePicker.OnTimeChangedListener(){
    public void onTimeChanged(TimePicker timePicker, int hourOfDay, int minute){
        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;
            timePicker.setCurrentMinute(minute);
            mIgnoreEvent=false;
        }

    }
};
Intoxicant answered 20/2, 2012 at 10:45 Comment(3)
but this code will not set the upper and bottom of values of time picker accordinglyLint
this is not working above lollipop, can you give alternate solution for this ?Turino
Ankit Thakkar is right. More precisely, it's specifically the clock layout that is problematic. It's due to the fact the minutePicker is null. I didn't find yet how to solve this.Slippage
P
9

The following worked for me.

First, in onCreate:

pickStartTime = (TimePicker)findViewById(R.id.StartTime);
pickStartTime.setOnTimeChangedListener(mStartTimeChangedListener);

Set the OnTimeChangedListener:

private TimePicker.OnTimeChangedListener mStartTimeChangedListener =
    new TimePicker.OnTimeChangedListener() {

    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
        updateDisplay(view, startDate, hourOfDay, minute);          
    }
};

Null OnTimeChangedListener (explained in comments in updateDisplay below):

private TimePicker.OnTimeChangedListener mNullTimeChangedListener =
    new TimePicker.OnTimeChangedListener() {

    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {

    }
};

private void updateDisplay(TimePicker timePicker, Date date, int hourOfDay, int minute) { 

    // do calculation of next time 
    int nextMinute = 0;     
    if (minute >= 45 && minute <= 59)
        nextMinute = 45;
    else if(minute >= 30)
        nextMinute = 30;
    else if(minute >= 15)
        nextMinute = 15;
    else if(minute > 0)
        nextMinute = 0;
    else {          
        nextMinute = 45;
    }

    // remove ontimechangedlistener to prevent stackoverflow/infinite loop
    timePicker.setOnTimeChangedListener(mNullTimeChangedListener);

    // set minute
    timePicker.setCurrentMinute(nextMinute);

    // hook up ontimechangedlistener again
    timePicker.setOnTimeChangedListener(mStartTimeChangedListener);

    // update the date variable for use elsewhere in code
    date.setMinutes(nextMinute);  
}
Palstave answered 24/6, 2010 at 4:44 Comment(2)
I just found a problem with my logic for determining the minute value. With the code above, the "+" button doesn't work. I'll post the updated code when I get it fixed.Palstave
We could get rid of some ugly code if this bug was fixed.Impractical
A
3

You have to write your own TimePicker. Not sure if you can extend the existing TimePicker and handle the button events on your own.

Adel answered 5/4, 2010 at 18:34 Comment(0)
T
3

I think I figured it out. Might be ghetto way but...

Here is what I did.

start_time.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {

            public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
                updateDisplay(hourOfDay, minute);
            }
        });

private void updateDisplay(int hourOfDay, int minute) {
                // do calculation of next time
                // nextTime = calculation of next time;

                // the processed boolean is to prevent infinite loop
        if (!processed) {
            start_time.setCurrentMinute(nextTime);  
                        processed = true;
        } else {
                        processed = false;
                }
    }
Tetrachord answered 5/4, 2010 at 18:57 Comment(0)
P
2
private void updateDisplay(TimePicker timePicker, int hourOfDay, int minute) {
    int nextMinute = 0;

    timePicker.setOnTimeChangedListener(mNullTimeChangedListener);

    if (minute >= 45 && minute <= 59) 
        nextMinute = 45;  
    else if (minute  >= 30) 
        nextMinute = 30;
    else if (minute >= 15) 
        nextMinute = 15;
    else if (minute > 0) 
        nextMinute = 0; 
    else { 
        nextMinute = 45; 
    }

    if (minute - nextMinute == 1) {
        if (minute >= 45 && minute <= 59) 
            nextMinute = 00; 
        else if(minute  >= 30) 
            nextMinute = 45;
        else if(minute >= 15) 
            nextMinute = 30;
        else if(minute > 0) 
            nextMinute = 15; 
        else { 
            nextMinute = 15; 
        }
    }

    timePicker.setCurrentMinute(nextMinute);

    timePicker.setOnTimeChangedListener(timePickerChangedListener);

}

Update display method modified for + and - buttons. Rest of the code is same as that from Andrew Dyer.

Psalmist answered 16/4, 2011 at 18:27 Comment(0)
S
2

I've come up with a solution based on some of the previous answers to this question, and some of my own additions. This solution notably overrides getCurrentMinute and setCurrentMinute, which by default return you the minute index, not the minute value (ie. if your minute interval is 15 and the picker had a displayed minute of 30, it would return 2 without this code).

This solution will also rollover minutes greater than the max interval value (again if your interval is 15, any minutes > 45 will set the minute value to 0 and increment the hour value).

NOTE: This is tested and working on Android 4.4 and 5.0.

public class CustomIntervalTimePicker extends TimePicker {

    private static final int TIME_PICKER_MINUTE_INTERVAL = 15;
    private OnTimeChangedListener timeChangedListener;

    public CustomIntervalTimePicker(Context context, AttributeSet attrs) {
        super(context, attrs);

        try {
            Class<?> classForId = Class.forName("com.android.internal.R$id");
            Field field = classForId.getField("minute");

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

    private int maxMinuteIndex() {
        return (60 / TIME_PICKER_MINUTE_INTERVAL) - 1;
    }

    @Override
    public void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener) {
        super.setOnTimeChangedListener(internalTimeChangedListener);
        this.timeChangedListener = onTimeChangedListener;
    }

    @Override
    public Integer getCurrentMinute() {
        return super.getCurrentMinute() * TIME_PICKER_MINUTE_INTERVAL;
    }

    @Override
    public void setCurrentMinute(Integer currentMinute) {
        int cleanMinute = currentMinute / TIME_PICKER_MINUTE_INTERVAL;
        if(currentMinute % TIME_PICKER_MINUTE_INTERVAL > 0) {
            if(cleanMinute == maxMinuteIndex()) {
                cleanMinute = 0;
                setCurrentHour(getCurrentHour()+1);
            } else {
                cleanMinute++;
            }
        }
        super.setCurrentMinute(cleanMinute);
    }

    // We want to proxy all the calls to our member variable OnTimeChangedListener with our own
    // internal listener in order to make sure our overridden getCurrentMinute is called. Without
    // this some versions of android return the underlying minute index.
    private OnTimeChangedListener internalTimeChangedListener = new OnTimeChangedListener() {
        @Override
        public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
            timeChangedListener.onTimeChanged(view, getCurrentHour(), getCurrentMinute());
        }
    };
}
Spinous answered 4/5, 2015 at 22:10 Comment(2)
AttributeSet attrs what is the attrs parameter when I want to use your code? please suggest me any solution How to use thisSpreader
used your code it accept 15 min difference but not showing on timepicker 15 min value.. how to use attributeset here.. plz explain..Spreader
P
1

First of all I'd like to thank Andrew for overcoming stackoverflow error(infinite loop).My logic to increment time by 15 min is something like this.Declare int previousMinuteSet = 0 as a member variable in the given class.

// remove ontimechangedlistener to prevent stackoverflow/infinite loop timePicker.setOnTimeChangedListener(mNullTimeChangedListener);

        if((minute - previousMinuteSet  == 1) || (minute - previousMinuteSet  == 15) || (minute - previousMinuteSet  == -45)) {
            // set hour
            timePicker.setCurrentHour((hourOfDay + minute / 45) % 12);
            // set minute
            timePicker.setCurrentMinute((minute + 14) % 60);
        } else {
            // set hour
            timePicker.setCurrentHour(hourOfDay);
            // set minute
            timePicker.setCurrentMinute(minute);

        }
        previousMinuteSet = minute;
        // hook up ontimechangedlistener again
        timePicker.setOnTimeChangedListener(timePickerChangedListener);

Hope this might would be helpful for others.The code I replaced in updateDisplay method of Andrew, apart from that everything was same.

Psalmist answered 19/3, 2011 at 20:23 Comment(0)
S
0

Here's the version I wrote. It's C# code because I'm using Xamarin, but I hope it won't be harder for anyone to translate it to Java than for me it is to perform vica versa translation when I need to copy a piece of Java code.

It's a bit different from standard TimePicker in that it's top and bottom border is not continuous, but it's a flaw some people will find insignificant.

I could have done a better job in making setting custom minutes interval easier and not making you to hardcode the interval values in the implementation, but I believe you can polish this solution if you want to very quickly!

HourPickerMapper.cs

public class HourPickerMapper
{
    public HourPickerMapper() { }

    public int MapValue(int hour)
    {
        return hour;
    }

    public int MapNumber(int number)
    {
        return number;
    }

    public void InitNumberPicker(NumberPicker numberPicker)
    {
        int[] numbers = new int[24];
        for (var i = 0; i < numbers.Length; i++)
        {
            numbers[i] = i;
        }
        var displayed = numbers.Select(_ => $"{_:00}").ToArray();

        numberPicker.SetDisplayedValues(displayed);
        numberPicker.MinValue = 0;
        numberPicker.MaxValue = displayed.Length - 1;
    }
}

MinutePickerMapper.cs

public class MinutePickerMapper
{
    public MinutePickerMapper() { }

    public int MapValue(int value)
    {
        return (int)Math.Floor(value / 10.0);
    }

    public int MapNumber(int number)
    {
        return number * 10;
    }

    public void InitNumberPicker(NumberPicker numberPicker)
    {
        int[] numbers = new int[6];
        for (var i = 0; i < numbers.Length; i++)
        {
            numbers[i] = i * 10;
        }
        var displayed = numbers.Select(_ => _.ToString()).ToArray();

        numberPicker.SetDisplayedValues(displayed);
        numberPicker.MinValue = 0;
        numberPicker.MaxValue = displayed.Length - 1;
    }
}

And here's the example of usage, a DialogFragment

public class CustomDateTimePickerDialogFragment : Android.Support.V4.App.DialogFragment
{
    private DateTime _dt;
    private NumberPicker _datePicker, _hourPicker, _minutePicker;
    private DatePickerMapper _datePickerMapper;
    private HourPickerMapper _hourPickerMapper;
    private MinutePickerMapper _minutePickerMapper;

    public event EventHandler<DateTimeSetEventArgs> DateTimeSetEvent;
    public CustomDateTimePickerDialogFragment()
    {
        _dt = DateTime.Now + new TimeSpan(24, 0, 0); // now + 1 day
    }

    public CustomDateTimePickerDialogFragment(DateTime dt)
    {
        _dt = dt;
        if (dt == null)
        {
            _dt = DateTime.Now + new TimeSpan(24, 0, 0); // now + 1 day
        }
    }

    public override Dialog OnCreateDialog(Bundle savedInstanceState)
    {
        AlertDialog.Builder builder = new AlertDialog.Builder(Context);
        builder.SetNeutralButton(Resource.String.dialog_datetime_now, (sender, e) => 
        {
            var eventArgs = new DateTimeSetEventArgs();
            DateTimeSetEvent.Invoke(this, eventArgs);
        });
        builder.SetPositiveButton(Resource.String.dialog_ok, (sender, e) =>
        {
            var hour = _hourPickerMapper.MapNumber(_hourPicker.Value);
            var minute = _minutePickerMapper.MapNumber(_minutePicker.Value);
            var date = _datePickerMapper.MapNumber(_datePicker.Value);
            var eventArgs = new DateTimeSetEventArgs(new DateTime(date.Year, date.Month, date.Day, hour, minute, 0));
            DateTimeSetEvent.Invoke(this, eventArgs);
            Dismiss();
        });
        var dialog = builder.Create();
        dialog.SetView(createDateTimeView(dialog.LayoutInflater));

        _datePicker.Value = _datePickerMapper.MapValue(_dt);
        _hourPicker.Value = _hourPickerMapper.MapValue(_dt.Hour);
        _minutePicker.Value = _minutePickerMapper.MapValue(_dt.Minute);

        return dialog;
    }

    private View createDateTimeView(LayoutInflater inflater)
    {
        View view = inflater.Inflate(Resource.Layout.dialog_custom_datetime_picker, null);

        _datePicker = view.FindViewById<NumberPicker>(Resource.Id.datePicker);
        _datePickerMapper = new DatePickerMapper(DateTime.Now, 10);
        _datePickerMapper.InitNumberPicker(_datePicker);

        var now = DateTime.Now;
        _datePicker.Value = _datePickerMapper.MapValue(now);

        _minutePicker = view.FindViewById<NumberPicker>(Resource.Id.minutePicker);
        _minutePickerMapper = new MinutePickerMapper();
        _minutePickerMapper.InitNumberPicker(_minutePicker);
        _minutePicker.Value = _minutePickerMapper.MapValue(now.Minute);

        _hourPicker = view.FindViewById<NumberPicker>(Resource.Id.hourPicker);
        _hourPickerMapper = new HourPickerMapper();
        _hourPickerMapper.InitNumberPicker(_hourPicker);
        _hourPicker.Value = _hourPickerMapper.MapValue(now.Hour);

        return view;
    }

    public class DateTimeSetEventArgs : EventArgs
    {
        public DateTimeSetEventArgs(DateTime dt)
        {
            IsNow = false;
            DT = dt;
        }

        public DateTimeSetEventArgs()
        {
            IsNow = true;
        }

        public DateTime DT { get; }
        public bool IsNow { get; }
    }
}

dialog_custom_datetime_picker.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="@dimen/dialog_padding"
    >
  <!-- Layout for the DatePicker -->
  <LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
  >
     <LinearLayout
      android:orientation="horizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:gravity="center_vertical"
      >
      <NumberPicker
        android:id="@+id/datePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants"
        />
      <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=" "
        />
      <NumberPicker
        android:id="@+id/hourPicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants"
        />
         <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text=":"
          />
      <NumberPicker
        android:id="@+id/minutePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:descendantFocusability="blocksDescendants"
        />       
    </LinearLayout>  
  </LinearLayout>
</LinearLayout>
Spawn answered 17/2, 2016 at 18:37 Comment(0)
C
0

TimePicker basically constists of two NumberPickers, for hours and minutes. Using Kotlin, you can use any minute interval using this function: https://mcmap.net/q/331498/-how-do-i-change-the-android-timepicker-minute-intervals

Cuirass answered 3/6, 2020 at 12:20 Comment(0)
L
0

This is how I succeded to only show :00, :15, :30 and :45 minute option, after the user selects the hour.

TimePickerDialog tpd = TimePickerDialog.newInstance( this, DateTime.now().get(Calendar.HOUR_OF_DAY), DateTime.now().get(Calendar.MINUTE), true); tpd.setTimeInterval(1, 15);

tpd.setOkText(getString(R.string.lbl_ok));

tpd.setCancelText(getString(R.string.lbl_cancel));

tpd.show(getSupportFragmentManager(), tagName);

Luteous answered 22/8, 2020 at 13:2 Comment(0)
C
0

You cant without extending TimePicker. Try this solutions:

import android.content.Context
import android.util.AttributeSet
import android.widget.NumberPicker
import android.widget.TimePicker
import androidx.databinding.BindingAdapter
import java.lang.reflect.Field
import java.util.*


class TimePickerInterval @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TimePicker(context, attrs, defStyleAttr) {

    private var MINUTE_INTERVAL = 1
    override fun getCurrentMinute(): Int {
        return super.getCurrentMinute() * MINUTE_INTERVAL
    }

    override fun getMinute(): Int {
        return super.getMinute() * MINUTE_INTERVAL
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        setUp()
    }

    private fun setUp() {
        try {
            val classForid = Class.forName("com.android.internal.R\$id")
            val field: Field = classForid.getField("minute")
            val mMinuteSpinner = findViewById<NumberPicker>(field.getInt(null))
            mMinuteSpinner.minValue = 0
            mMinuteSpinner.maxValue = 60 / MINUTE_INTERVAL - 1
            val displayedValues: MutableList<String> = ArrayList()
            var i = 0
            while (i < 60) {
                displayedValues.add(String.format("%02d", i))
                i += MINUTE_INTERVAL
            }
            mMinuteSpinner.displayedValues = displayedValues.toTypedArray()

        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun setOnTimeChangedListener(onTimeChangedListener: OnTimeChangedListener) {
        super.setOnTimeChangedListener { tp, hour, minute ->
            onTimeChangedListener.onTimeChanged(tp, hour, minute * MINUTE_INTERVAL)
        }
    }

    override fun setMinute(minute: Int) {
        super.setMinute(minute/MINUTE_INTERVAL)
    }

    companion object {
        @JvmStatic
        @BindingAdapter("time_picker_set_minute_interval")
        fun setInterval(view: TimePickerInterval, interval: Int?) {
            interval?.let {
                view.MINUTE_INTERVAL = interval
                view.setUp()
            }
        }
    }
}

In your XML:

    <com.gixon.shared.widgets.TimePickerInterval
        android:id="@+id/tp_to"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:timePickerMode="spinner"
        time_picker_set_minute_interval="@{5}"
        />
Coucal answered 8/9, 2021 at 18:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.