android intervals android-timepicker

Mostrar TimePicker con intervalos de minutos en Android



intervals android-timepicker (10)

Mi aplicación muestra un TimePickerDialog para establecer una hora. Quiero que timePickerDialog muestre los minutos con un intervalo de 5 minutos.

Esto funciona bien con este código:

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; } }

Aunque solo se pueden seleccionar minutos con un intervalo de cinco minutos, el cuadro de diálogo timepicker se ve así:

No sé cómo los minutos también muestran el rango de 5 minutos, como en esta imagen:

He buscado pero no puedo encontrar la solución.


Basado en la respuesta de Tanmay Mandal que se muestra arriba, he implementado una solución para el widget TimePicker (no el TimePickerDialog). El truco aquí es sustituir el elemento TimePicker original en el diseño de la actividad por un elemento LinearLayout, para agregar nuestro TimePicker personalizado mediante programación. Vea el siguiente ejemplo:

import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.widget.NumberPicker; import android.widget.TimePicker; public class MyTimePicker extends TimePicker { private static final int TIME_PICKER_INTERVAL = 5; public MyTimePicker(Context context) { super(context); } @Override public Integer getCurrentMinute() { return super.getCurrentMinute()*TIME_PICKER_INTERVAL; } @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(0); mMinuteSpinner.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)); mMinuteSpinner.setDisplayedValues(displayedValues.toArray(new String[0])); } catch (Exception e) { e.printStackTrace(); } } }

Y para nuestra actividad:

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout ll = (LinearLayout) findViewById(R.id.myLinearLayout); ll.removeAllViews(); MyTimePicker tp = new MyTimePicker(this); tp.setIs24HourView(true); Calendar cal = Calendar.getInstance(); // Current time tp.setCurrentHour(cal.get(Calendar.HOUR_OF_DAY)); tp.setCurrentMinute(cal.get(Calendar.MINUTE)/5); // Aprox current minute ll.addView(tp); }


Como dijo @anddev84, puedes hacerlo con tu propio TimePickerDialog personalizado.

Sin embargo, eche un vistazo al código fuente que puede encontrar:

  1. TimePickerDialog es un diseño de marco, vea este file . Y solo contiene un TimePicker
  2. El widget TimePicker es solo un diseño lineal, mira este file . Y puedes ver que el minuto que gira es un NumberPicker
  3. Consulte el código de NumberPicker , encontrará que tiene un método público setDisplayedValues ​​(String [] displayedValues)

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

Entonces, con esta información, supongo que puedes simplemente personalizar tu propio cuadro de diálogo del selector de tiempo con minutos limitados mostrados.


Esta impresionante biblioteca, MaterialDateTimePicker crea hermosos marcadores de tiempo de estilo.

Puede usar uno de los siguientes métodos para definir su intervalo:

  • setSelectableTimes (Timepoint [] times) Puede pasar una variedad de Timepoints. Estos valores son las únicas selecciones válidas en el selector. setMinTime (Timepoint time) y setMaxTime (Timepoint time) recortarán aún más esta lista.

  • setTimeInterval (int hourInterval, int minuteInterval, int secondInterval) Establece el intervalo de tiempos seleccionables en TimePickerDialog. Este es un contenedor de conveniencia alrededor de setSelectableTimes


He agregado una excelente respuesta aceptada anteriormente. El problema es que, al menos en algunas versiones de Android, cuando cambia la hora seleccionada, reemplazará el título del diálogo con un valor de tiempo incorrecto. No puede anular el método ofensivo, updateTitle (), pero puede interceptar la llamada en onTimeChanged () y no llamar a super o llamarlo con argumentos fijos.

Desconecté el mío de si se había llamado al método setTitle () con una ID de cadena distinta de cero, pero solo se podía tener un getter / setter para boolean o lo que fuera.

@Override public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { if (autoTitle) { // Super will call a private updateTitle() method, so lets make // sure it has the right minute value. super.onTimeChanged(view, hourOfDay, minute * TIME_PICKER_INTERVAL); } else { // do nothing } } @Override public void setTitle(int id) { super.setTitle(id); autoTitle = (id == 0); } ... private boolean autoTitle = true;


La respuesta anterior funciona realmente bien para la versión anterior de Android, pero no funcionó para mí en Android 7 Nougat, básicamente el selector de fecha se cambió por completo para usar el modo Reloj ... Combino el código propuesto aquí con https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f , luego establece de manera predeterminada el modo TimePickerDialog para mostrar los controles de Spinner, y ejecuta el código para mostrar solo intervalos de 15 minutos en mi caso.

El código se publica aquí https://gist.github.com/smaugho/14dae83f3284fa05455ee0a9e4f13099

public class CustomTimePickerDialog extends TimePickerDialog { private final static int TIME_PICKER_INTERVAL = 15; private TimePicker timePicker; private final OnTimeSetListener callback; public HorekoTimePicker(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView) { super(context, callBack, hourOfDay, minute/TIME_PICKER_INTERVAL, is24HourView); this.callback = callBack; fixSpinner(context, hourOfDay, minute, is24HourView); } /** * Workaround for this bug: https://code.google.com/p/android/issues/detail?id=222208 * In Android 7.0 Nougat, spinner mode for the TimePicker in TimePickerDialog is * incorrectly displayed as clock, even when the theme specifies otherwise, such as: * * <resources> * <style name="Theme.MyApp" parent="Theme.AppCompat.Light.NoActionBar"> * <item name="android:timePickerStyle">@style/Widget.MyApp.TimePicker</item> * </style> * * <style name="Widget.MyApp.TimePicker" parent="android:Widget.Material.TimePicker"> * <item name="android:timePickerMode">spinner</item> * </style> * </resources> * * May also pass TimePickerDialog.THEME_HOLO_LIGHT as an argument to the constructor, * as this theme has the TimePickerMode set to spinner. * * Taken from: https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f */ 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 final int MODE_SPINNER = 1; 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) 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 { // TimePickerSpinnerDelegate was initially misnamed TimePickerClockDelegate in API 21! spinnerDelegateClass = Class.forName("android.widget.TimePickerClockDelegate"); } // In 7.0 Nougat for some reason the timePickerMode is ignored and the delegate is 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); } setTimeIntervals(); } } 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; } @Override protected void onStop() { } /* * Feature #363: (Un)availability times in 15min interval * https://abix.webhop.net/redmine/issues/363 * Solution extracted from * http://.com/questions/20214547/show-timepicker-with-minutes-intervals-in-android */ @Override public void onClick(DialogInterface dialog, int which) { super.onClick(dialog, which); if (callback != null && timePicker != null) { timePicker.clearFocus(); callback.onTimeSet(timePicker, timePicker.getCurrentHour(), timePicker.getCurrentMinute()*TIME_PICKER_INTERVAL); } } private void setTimeIntervals() { try { Class<?> classForid = Class.forName("com.android.internal.R$id"); 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<String>(); 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(); } }

}


Luchado con 30 minutos de intervalo más de una hora. Podría luchar más si no viera el comentario de @Lee. Así que solo publique un código de diálogo completo con un intervalo de 30 minutos:

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; } }


Si TimePickerDialog el código de TimePickerDialog , no parece que le den una forma de modificar directamente el TimePicker antes de que se muestre al usuario y verá los "minutos incorrectos" que muestra en la imagen. Ver TimePickerDialog.java

Mi recomendación es crear tu propio TimePickerDialog, basando el diseño en el de Android. Puede sonar desalentador al principio, pero

  1. De esta forma, puede personalizar la implementación como lo desee, incluyendo la inicialización de los valores de TimePicker para mostrar los minutos (como se menciona here ), y también
  2. en realidad no debería ser muy difícil, el Android TimePickerDialog.java en sí mismo es de solo 160 líneas, muy manejable.

Si no usa el mismo selector de tiempo (no reloj) en Android 5+ simplemente cambie el tema. Puede cambiar directamente en el constructor:

public CustomTimePickerDialog(Context context, OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView, int time_interval) { super(context, TimePickerDialog.THEME_HOLO_LIGHT, callBack, hourOfDay, minute / time_interval, is24HourView); this.TIME_PICKER_INTERVAL = time_interval; this.callback = callBack; }


Use la siguiente clase personalizada llamada CustomTimePickerDialog , que creo que resuelve su problema.

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(); } } }

Aquí está la captura de pantalla de demostración.


/** * 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); } }