2010-04-05 28 views
36

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

que significa si son las 12:28 ahora, muestre 12:30 y haga clic en el botón + y - aumentará y disminuirá en 15?

Gracias,

Tee

Respuesta

3

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

3

Creo que lo descubrí. Puede ser gueto, pero ...

Esto es 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; 
       } 
    } 
8

Lo siguiente funcionó para mí.

primer lugar, en onCreate:

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

Ajuste el OnTimeChangedListener:

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

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

nulo OnTimeChangedListener (se explica en los comentarios en updateDisplay abajo):

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

acabo de encontrar un problema con mi lógica para determinar el valor de minutos. Con el código anterior, el botón "+" no funciona. Publicaré el código actualizado cuando lo solucione. –

+0

Podríamos deshacernos de algún código feo si se solucionó este error (http://code.google.com/p/android/issues/detail?id=27653). – user250343

1

En primer lugar me' Me gustaría agradecer a Andrew por superar el error de stackoverflow (bucle infinito). Mi lógica para incrementar el tiempo b y 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); 

Hope esto podría sería útil para el código others.The He sustituido en el método updateDisplay de Andrew, aparte de eso, todo era igual.

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

} 

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

19

aquí está mi versión donde se puede 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; 
     } 

    } 
}; 
+3

pero este código no configurará la parte superior e inferior de los valores del selector de tiempo según corresponda – ANinJa

+1

esto no funciona por encima de lollipop, ¿puede dar una solución alternativa para esto? –

+0

Ankit Thakkar tiene razón. Más precisamente, es específicamente el diseño del reloj lo que es problemático. Es debido al hecho de que minutePicker es nulo. No he encontrado todavía cómo solucionar esto. – PAD

18

Crear un archivo XML y el nombre de 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> 

crear ahora la 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<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(); 
      } 
    } 
} 
+0

La hora no cambia cuando se mueve entre 45 y 00. Cambio después de dos repeticiones solamente ... – schabluk

+1

@schabluk tiene razón. Es un error. En realidad, agregué un minuto dos veces. Sin hacerlo, no pudo desplazarse automáticamente por los minutos. Intentaré solucionarlo y actualizaré mi respuesta cuando la solucione. – Ali

+1

Ojalá pueda aplicar esta solución, pero Android Studio se queja de 'ClassNotFoundException' en' Class.forName ("com.android.internal.R $ id") 'incluso si android.jar ya existe en las Bibliotecas externas. – CallMeLaNN

2

He encontrado una solución basada en algunas de las respuestas anteriores a esta pregunta, y algunas de las mías dditions. 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 los minutos 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<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()); 
     } 
    }; 
} 
+0

AttributeSet attrs ¿cuál es el parámetro attrs cuando quiero usar tu código? por favor sugiérame cualquier solución Cómo usar este – Asmi

+0

usó su código, acepta 15 min de diferencia, pero no se muestra en timepicker 15 min value ... cómo usar attributeset here ... por favor explique ... – Asmi

+0

Necesito su ayuda para usar su código help me si puedes.. – Asmi

0

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 para facilitar 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 es el ejemplo de uso aquí, 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<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> 
Cuestiones relacionadas