Android – TimePicker minutos para 15

¿Puedo controlar la vista TimePicker de Android para mostrar los minutos en intervalos de 15 minutos?

Significando si ahora son las 12:28, muestra 12:30 y haciendo clic en el botón + y – boostá y disminuirá en 15?

Gracias,

Tee

Aquí está mi versión donde puedes establecer el intervalo:

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

Cree un archivo xml y asígnele el nombre activity_time_picker.xml

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

ahora crea una clase de actividad como esta

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

Lo siguiente funcionó para mí.

Primero, en onCreate:

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

Establezca OnTimeChangedListener:

 private TimePicker.OnTimeChangedListener mStartTimeChangedListener = new TimePicker.OnTimeChangedListener() { public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { updateDisplay(view, startDate, hourOfDay, minute); } }; 

Null OnTimeChangedListener (explicado en comentarios en updateDisplay a continuación):

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

Tienes que escribir tu propio TimePicker. No estoy seguro de si puede ampliar el TimePicker existente y manejar los eventos del botón por su cuenta.

Creo que lo descubrí. Podría ser un gueto, pero …

Aquí esta lo que hice.

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

Actualizar el método de visualización modificado para los botones + y -. El rest del código es el mismo que el de Andrew Dyer.

He encontrado una solución basada en algunas de las respuestas anteriores a esta pregunta, y algunas de mis propias adiciones. Esta solución sobrescribe notablemente getCurrentMinute y setCurrentMinute, que por defecto le devuelve el índice de minutos, no el valor de minutos (es decir, si su intervalo de minutos es 15 y el selector tenía un minuto mostrado de 30, devolvería 2 sin este código).

Esta solución también transferirá minutos mayores que el valor del intervalo máximo (nuevamente, si su intervalo es 15, cualquier minuto> 45 configurará el valor de minuto en 0 e incrementará el valor de la hora).

NOTA: Esto se prueba y funciona en Android 4.4 y 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 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()); } }; } 

En primer lugar, me gustaría agradecer a Andrew por superar el error de stackoverflow (bucle infinito). Mi lógica para incrementar el tiempo en 15 min es algo como esto. Declarar int previousMinuteSet = 0 como una variable miembro en la clase dada.

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

Espero que esto pueda ser útil para otros. El código que reemplacé en el método updateDisplay de Andrew, aparte de eso, todo era lo mismo.

Aquí está la versión que escribí. Es código C # porque estoy usando Xamarin, pero espero que no sea más difícil para cualquiera traducirlo a Java que para mí es realizar la traducción vica versa cuando necesito copiar una parte del código Java.

Es un poco diferente del TimePicker estándar en que su borde superior e inferior no es continuo, pero es un defecto que a algunas personas les parecerá insignificante.

Podría haber hecho un mejor trabajo facilitando la configuración del intervalo de minutos personalizado y no hacer que codifique los valores de intervalo en la implementación, ¡pero creo que puede pulir esta solución si lo desea rápidamente!

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

Y aquí está el ejemplo de uso, un 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 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(Resource.Id.datePicker); _datePickerMapper = new DatePickerMapper(DateTime.Now, 10); _datePickerMapper.InitNumberPicker(_datePicker); var now = DateTime.Now; _datePicker.Value = _datePickerMapper.MapValue(now); _minutePicker = view.FindViewById(Resource.Id.minutePicker); _minutePickerMapper = new MinutePickerMapper(); _minutePickerMapper.InitNumberPicker(_minutePicker); _minutePicker.Value = _minutePickerMapper.MapValue(now.Minute); _hourPicker = view.FindViewById(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"?>