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?
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?
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();
}
}
}
ClassNotFoundException
on Class.forName("com.android.internal.R$id")
even if android.jar already exist in the External Libraries. –
Guido com.android.internal.R$id
stands for? –
Damnable 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;
}
}
};
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);
}
You have to write your own TimePicker. Not sure if you can extend the existing TimePicker and handle the button events on your own.
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;
}
}
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.
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());
}
};
}
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.
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>
TimePicker
basically constists of two NumberPicker
s, 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
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);
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}"
/>
© 2022 - 2024 — McMap. All rights reserved.