Android TimePickerDialog establece el tiempo máximo

Estoy buscando una manera de establecer el máximo y mínimo tiempo seleccionable en un TimePickerDialog Android, y para cambiar el intervalo de minutos predeterminado de 1 minuto a 5 minutos,

¡Pensé que era fácil, pero no puedo encontrar la manera!

Esta es una extensión de la respuesta de los violinistas. De alguna manera, TimePickerDialog no configura el onTimeChangedListener en algunas versiones de Android:

ex. http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.1_r1.2/android/app/TimePickerDialog.java

¡El método onTimeChanged para eso nunca se llama! Actualmente, la mejor solución para este problema consiste en codificar un TimePickerDialog personalizado con la lógica min / max de fiddler.

El trabajo más feo alrededor es esto. (Agregar el oyente utilizando reflexiones) También actualizo el título para mostrar la hora seleccionada actualmente.

 package com.mysuger.android.dialogs; import java.lang.reflect.Field; import java.text.DateFormat; import java.util.Calendar; import android.app.TimePickerDialog; import android.content.Context; import android.widget.TimePicker; /** * A time dialog that allows setting a min and max time. * */ public class RangeTimePickerDialog extends TimePickerDialog { private int minHour = -1; private int minMinute = -1; private int maxHour = 25; private int maxMinute = 25; private int currentHour = 0; private int currentMinute = 0; private Calendar calendar = Calendar.getInstance(); private DateFormat dateFormat; public RangeTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) { super(context, callBack, hourOfDay, minute, is24HourView); currentHour = hourOfDay; currentMinute = minute; dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT); try { Class superclass = getClass().getSuperclass(); Field mTimePickerField = superclass.getDeclaredField("mTimePicker"); mTimePickerField.setAccessible(true); TimePicker mTimePicker = (TimePicker) mTimePickerField.get(this); mTimePicker.setOnTimeChangedListener(this); } catch (NoSuchFieldException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } } public void setMin(int hour, int minute) { minHour = hour; minMinute = minute; } public void setMax(int hour, int minute) { maxHour = hour; maxMinute = minute; } @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { boolean validTime = true; if (hourOfDay < minHour || (hourOfDay == minHour && minute < minMinute)){ validTime = false; } if (hourOfDay > maxHour || (hourOfDay == maxHour && minute > maxMinute)){ validTime = false; } if (validTime) { currentHour = hourOfDay; currentMinute = minute; } updateTime(currentHour, currentMinute); updateDialogTitle(view, currentHour, currentMinute); } private void updateDialogTitle(TimePicker timePicker, int hourOfDay, int minute) { calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); calendar.set(Calendar.MINUTE, minute); String title = dateFormat.format(calendar.getTime()); setTitle(title); } } 

Puedes usar esto como punto de partida.

Extendí TimePickerDialog y agregué 2 métodos setMin y setMax .

En el método onTimeChanged , compruebo que la nueva hora sea válida con respecto a los tiempos min / max.

Todavía necesita un poco de pulido, aunque …

 public class BoundTimePickerDialog extends TimePickerDialog { private int minHour = -1, minMinute = -1, maxHour = 100, maxMinute = 100; private int currentHour, currentMinute; public BoundTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) { super(context, callBack, hourOfDay, minute, is24HourView); } public void setMin(int hour, int minute) { minHour = hour; minMinute = minute; } public void setMax(int hour, int minute) { maxHour = hour; maxMinute = minute; } @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { super.onTimeChanged(view, hourOfDay, minute); boolean validTime; if(hourOfDay < minHour) { validTime = false; } else if(hourOfDay == minHour) { validTime = minute >= minMinute; } else if(hourOfDay == maxHour) { validTime = minute <= maxMinute; } else { validTime = true; } if(validTime) { currentHour = hourOfDay; currentMinute = minute; } else { updateTime(currentHour, currentMinute); } } } 

Para lolipop y la versión superior de Android, puedes usar esta clase modificada RangeTimePickerDialog

(Desde lolipop, Timepicker utiliza el modo de reloj (diseño de material) como predeterminado para que la clase personalizada anterior no funcione. Podemos cambiar el modo a spinner para la versión más reciente y podemos reutilizar la clase)

 public class RangeTimePickerDialog extends TimePickerDialog { private int minHour = -1; private int minMinute = -1; private int maxHour = 25; private int maxMinute = 25; private int currentHour = 0; private int currentMinute = 0; private Calendar calendar = Calendar.getInstance(); private DateFormat dateFormat; public RangeTimePickerDialog(Context context, int dialogTheme, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) { super(context, callBack, hourOfDay, minute, is24HourView); currentHour = hourOfDay; currentMinute = minute; dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT); fixSpinner(context, hourOfDay, minute, is24HourView); try { Class superclass = getClass().getSuperclass(); Field mTimePickerField = superclass.getDeclaredField("mTimePicker"); mTimePickerField.setAccessible(true); TimePicker mTimePicker = (TimePicker) mTimePickerField.get(this); mTimePicker.setOnTimeChangedListener(this); } catch (NoSuchFieldException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } } public void setMin(int hour, int minute) { minHour = hour; minMinute = minute; } public void setMax(int hour, int minute) { maxHour = hour; maxMinute = minute; } @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { boolean validTime = true; if (hourOfDay < minHour || (hourOfDay == minHour && minute < minMinute)){ validTime = false; } if (hourOfDay > maxHour || (hourOfDay == maxHour && minute > maxMinute)){ validTime = false; } if (validTime) { currentHour = hourOfDay; currentMinute = minute; } updateTime(currentHour, currentMinute); updateDialogTitle(view, currentHour, currentMinute); } private void updateDialogTitle(TimePicker timePicker, int hourOfDay, int minute) { calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); calendar.set(Calendar.MINUTE, minute); String title = dateFormat.format(calendar.getTime()); setTitle(title); } private void fixSpinner(Context context, int hourOfDay, int minute, boolean is24HourView) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // android:timePickerMode spinner and clock began in Lollipop try { // Get the theme's android:timePickerMode //two modes are available clock mode and spinner mode ... selecting spinner mode for latest versions final int MODE_SPINNER = 2; Class styleableClass = Class.forName("com.android.internal.R$styleable"); Field timePickerStyleableField = styleableClass.getField("TimePicker"); int[] timePickerStyleable = (int[]) timePickerStyleableField.get(null); final TypedArray a = context.obtainStyledAttributes(null, timePickerStyleable, android.R.attr.timePickerStyle, 0); Field timePickerModeStyleableField = styleableClass.getField("TimePicker_timePickerMode"); int timePickerModeStyleable = timePickerModeStyleableField.getInt(null); final int mode = a.getInt(timePickerModeStyleable, MODE_SPINNER); a.recycle(); if (mode == MODE_SPINNER) { TimePicker timePicker = (TimePicker) findField(TimePickerDialog.class, TimePicker.class, "mTimePicker").get(this); Class delegateClass = Class.forName("android.widget.TimePicker$TimePickerDelegate"); Field delegateField = findField(TimePicker.class, delegateClass, "mDelegate"); Object delegate = delegateField.get(timePicker); Class spinnerDelegateClass; if (Build.VERSION.SDK_INT != Build.VERSION_CODES.LOLLIPOP) { spinnerDelegateClass = Class.forName("android.widget.TimePickerSpinnerDelegate"); } else { spinnerDelegateClass = Class.forName("android.widget.TimePickerClockDelegate"); } if (delegate.getClass() != spinnerDelegateClass) { delegateField.set(timePicker, null); // throw out the TimePickerClockDelegate! timePicker.removeAllViews(); // remove the TimePickerClockDelegate views Constructor spinnerDelegateConstructor = spinnerDelegateClass.getConstructor(TimePicker.class, Context.class, AttributeSet.class, int.class, int.class); spinnerDelegateConstructor.setAccessible(true); // Instantiate a TimePickerSpinnerDelegate delegate = spinnerDelegateConstructor.newInstance(timePicker, context, null, android.R.attr.timePickerStyle, 0); delegateField.set(timePicker, delegate); // set the TimePicker.mDelegate to the spinner delegate // Set up the TimePicker again, with the TimePickerSpinnerDelegate timePicker.setIs24HourView(is24HourView); timePicker.setCurrentHour(hourOfDay); timePicker.setCurrentMinute(minute); timePicker.setOnTimeChangedListener(this); } } } catch (Exception e) { throw new RuntimeException(e); } } } private static Field findField(Class objectClass, Class fieldClass, String expectedName) { try { Field field = objectClass.getDeclaredField(expectedName); field.setAccessible(true); return field; } catch (NoSuchFieldException e) {} // ignore // search for it if it wasn't found under the expected ivar name for (Field searchField : objectClass.getDeclaredFields()) { if (searchField.getType() == fieldClass) { searchField.setAccessible(true); return searchField; } } return null; } } 

No hay métodos nativos para establecer el tiempo máximo / mínimo, pero tal vez funcione si extiende en onTimeChanged o tiempo de updateTime puede evitar que el tiempo se establezca en un valor fuera de sus límites.

Después del código re-factorizado de fiddler:

 public class RangeTimePickerDialog extends TimePickerDialog { private int mMinHour = -1; private int mMinMinute = -1; private int mMaxHour = 100; private int mMaxMinute = 100; private int mCurrentHour; private int mCurrentMinute; public RangeTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) { super(context, callBack, hourOfDay, minute, is24HourView); mCurrentHour = hourOfDay; mCurrentMinute = minute; // Somehow the onTimeChangedListener is not set by TimePickerDialog // in some Android Versions, so, Adding the listener using // reflections try { Class superclass = getClass().getSuperclass(); Field mTimePickerField = superclass.getDeclaredField("mTimePicker"); mTimePickerField.setAccessible(true); TimePicker mTimePicker = (TimePicker) mTimePickerField.get(this); mTimePicker.setOnTimeChangedListener(this); } catch (NoSuchFieldException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } } public void setMin(int hour, int minute) { mMinHour = hour; mMinMinute = minute; } public void setMax(int hour, int minute) { mMaxHour = hour; mMaxMinute = minute; } @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { super.onTimeChanged(view, hourOfDay, minute); boolean validTime; if (((hourOfDay < mMinHour ) || (hourOfDay == mMinHour && minute < mMinMinute)) || ((hourOfDay > mMaxHour) || (hourOfDay == mMaxHour && minute > mMaxMinute))) { validTime = false; } else { validTime = true; } if (validTime) { mCurrentHour = hourOfDay; mCurrentMinute = minute; } else { updateTime(mCurrentHour, mCurrentMinute); } } } 

Espero que esto pueda ser útil. Usé la biblioteca de tiempo Joda.

 public class RangeTimePicker extends TimePicker implements TimePicker.OnTimeChangedListener { private int mMinHour = -1; private int mMinMinute = -1; private int mMaxHour = 25; private int mMaxMinute = 61; private int mCurrentHour; private int mCurrentMinute; public RangeTimePicker(Context context) { super(context); setOnTimeChangedListener(this); } public RangeTimePicker(Context context, AttributeSet attrs) { super(context, attrs); setOnTimeChangedListener(this); } public RangeTimePicker(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setOnTimeChangedListener(this); } public void setMaxTime(int hourIn24, int minute) { mMaxHour = hourIn24; mMaxMinute = minute; LocalTime currentTime = LocalTime.now(); LocalTime maxTime = new LocalTime(mMaxHour, mMaxMinute); if (currentTime.isAfter(maxTime)) { this.setCurrentHour(mCurrentHour = currentTime.getHourOfDay()); this.setCurrentMinute( mCurrentMinute = currentTime.getMinuteOfHour()); } } public void setMinTime(int hourIn24, int minute) { mMinHour = hourIn24; mMinMinute = minute; LocalTime currentTime = LocalTime.now(); LocalTime minTime = new LocalTime(mMinHour, mMinMinute); if (currentTime.isBefore(minTime)) { this.setCurrentHour(mCurrentHour = minTime.getHourOfDay()); this.setCurrentMinute(mCurrentMinute = minTime.getMinuteOfHour()); } } @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { boolean validTime = true; if (hourOfDay < mMinHour || (hourOfDay == mMinHour && minute < mMinMinute)) { validTime = false; } if (hourOfDay > mMaxHour || (hourOfDay == mMaxHour && minute > mMaxMinute)) { validTime = false; } if (validTime) { mCurrentHour = hourOfDay; mCurrentMinute = minute; } setCurrentHour(mCurrentHour); setCurrentMinute(mCurrentMinute); } } 

Espero este trabajo. Funciona perfectamente conmigo …

Establezca el tiempo máximo para el selector de tiempo.

  timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() { @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { if (!mIsOnTimeChanged) { mIsOnTimeChanged = true; Calendar c = Calendar.getInstance(); //get the selected day if it is before today allow AM and PM trick //else apply rules int selected_year = datePicker.getYear(); int selected_month = datePicker.getMonth(); int selected_day = datePicker.getDayOfMonth(); int today = c.get(Calendar.DAY_OF_MONTH); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH); int hour = c.get(Calendar.HOUR); hour += 12; int min = c.get(Calendar.MINUTE); //Check if user enter hh | mm | more than current reset the timePicker with the current time //http://stackoverflow.com/questions/2659954/timepickerdialog-and-am-or-pm if ((hourOfDay == hour | hour < hourOfDay | hourOfDay > hour | hour > hourOfDay | minute > min) && (selected_month == month && selected_day == today && selected_year == year)) { int AM_PM_Value = hourOfDay; Calendar datetime = Calendar.getInstance(); int hour_without_24 = (hour - 12); if ((datetime.get(Calendar.AM_PM) == Calendar.AM) && (hourOfDay > hour_without_24)) { //set AM timePicker.setCurrentHour(hour - 12); } if (hourOfDay == (hour - 12) && minute > min) { timePicker.setCurrentMinute(min); } if (hourOfDay > hour && datetime.get(Calendar.AM_PM) != Calendar.AM) { timePicker.setCurrentHour(hour); if (minute > min) { timePicker.setCurrentMinute(min); } } } else if (selected_month != month | selected_day != today | selected_year != year) { } else if (hourOfDay == hour && minute > min) { timePicker.setCurrentMinute(min); } else if (hourOfDay > hour) { timePicker.setCurrentHour(hour); if (minute > min) { timePicker.setCurrentMinute(min); } } // isTimePickerChanged = true; String AM_PM; if (hourOfDay < 12) { AM_PM = "AM"; } else { AM_PM = "PM"; } //to set as 12 hour time_format = (hourOfDay + ":" + minute + ":" + "00"); if (hourOfDay > 12) { hourOfDay = (hourOfDay - 12); } st_time = (hourOfDay + ":" + pad(minute) + " " + AM_PM); mIsOnTimeChanged = false; } } }); 

Puede usar un TimePicker personalizado con reflection para establecer los valores.

  @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); try { Class classForid = Class.forName("com.android.internal.R$id"); Field field = classForid.getField("minute"); NumberPicker mMinuteSpinner = (NumberPicker) findViewById(field.getInt(null)); mMinuteSpinner.setMinValue(5); mMinuteSpinner.setMaxValue((60 / timeInterval) - 1); List displayedValues = new ArrayList<>(); for (int i = 0; i < 60; i += timeInterval) displayedValues.add(String.format("%02d", i)); mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0])); mMinuteSpinner.setWrapSelectorWheel(true); } catch (Exception e) { e.printStackTrace(); } } 

Para que pueda establecer qué valores quiere

Tomé la solución de @Zarooka como punto de partida. Creo que encontré un error. Si tenía una hora de inicio que ya estaba fuera de rango, ya no podía moverla más, porque cualquier “onChanged” estaba siendo rechazado. Es por eso que amplié setMax y setMin para ir a un rango válido cuando establezco los mins / maxs.

 package de.appdream.garooda.view; import java.util.Calendar; import java.util.Date; import android.app.TimePickerDialog; import android.content.Context; import android.text.format.DateFormat; import android.widget.TimePicker; import java.lang.reflect.Field; public class GaroodaTimePickerDialog extends TimePickerDialog { private int minHour = -1; private int minMinute = -1; private int maxHour = 25; private int maxMinute = 61; private int currentHour = 0; private int currentMinute = 0; private Calendar calendar = Calendar.getInstance(); //private DateFormat dateFormat; public GaroodaTimePickerDialog(Context context, OnTimeSetListener callBack, int hour, int minute, boolean is24HourView) { super(context, callBack, hour, minute, is24HourView); currentHour = hour; currentMinute = minute; //dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT); try { Class superclass = getClass().getSuperclass(); Field mTimePickerField = superclass.getDeclaredField("mTimePicker"); mTimePickerField.setAccessible(true); TimePicker mTimePicker = (TimePicker) mTimePickerField.get(this); mTimePicker.setOnTimeChangedListener(this); } catch (NoSuchFieldException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } } public void setMin(int hour, int minute) { minHour = hour; minMinute = minute; Calendar min = Calendar.getInstance(); Calendar existing = Calendar.getInstance(); min.set(Calendar.HOUR_OF_DAY, minHour); min.set(Calendar.MINUTE, minMinute); existing.set(Calendar.HOUR_OF_DAY, currentHour); existing.set(Calendar.MINUTE, currentMinute); if (existing.before(min)) { currentHour = minHour; currentMinute = minMinute; updateTime(currentHour, currentMinute); } } public void setMax(int hour, int minute) { maxHour = hour; maxMinute = minute; Calendar max = Calendar.getInstance(); Calendar existing = Calendar.getInstance(); max.set(Calendar.HOUR_OF_DAY, maxHour); max.set(Calendar.MINUTE, maxMinute); existing.set(Calendar.HOUR_OF_DAY, currentHour); existing.set(Calendar.MINUTE, currentMinute); if (existing.after(max)) { currentHour = maxHour; currentMinute = maxMinute; updateTime(currentHour, currentMinute); } } @Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { boolean validTime = true; if (hourOfDay < minHour || (hourOfDay == minHour && minute < minMinute)){ validTime = false; } if (hourOfDay > maxHour || (hourOfDay == maxHour && minute > maxMinute)){ validTime = false; } if (validTime) { currentHour = hourOfDay; currentMinute = minute; } updateTime(currentHour, currentMinute); updateDialogTitle(view, currentHour, currentMinute); } private void updateDialogTitle(TimePicker timePicker, int hourOfDay, int minute) { calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); calendar.set(Calendar.MINUTE, minute); //String title = dateFormat.format(calendar.getTime()); //setTitle(title); } }