Selector de hora de Android
Para proporcionarle al usuario una manera de seleccionar una hora, puede usar TimePicker. Normalmente, las aplicaciones de Android usan TimePicker
con TimePickerDialog para seleccionar un valor de tiempo, lo que ayuda a garantizar una interfaz coherente en los dispositivos y aplicaciones. TimePicker
permite a los usuarios seleccionar la hora del día en el modo de 24 horas o 12 horas a. m./p. m.
TimePickerDialog
es una clase auxiliar que encapsula TimePicker
en un cuadro de diálogo.
Información general
Las aplicaciones modernas de Android muestran TimePickerDialog
un DialogFragment. Esto permite a una aplicación mostrar TimePicker
como un cuadro de diálogo emergente o insertarlo en una actividad. Además, DialogFragment
administra el ciclo de vida y la visualización del cuadro de diálogo, lo que reduce la cantidad de código que se debe implementar.
En esta guía se muestra cómo usar TimePickerDialog
, encapsulado en un DialogFragment
. La aplicación de ejemplo muestra TimePickerDialog
como un cuadro de diálogo modal cuando el usuario hace clic en un botón en una actividad. Cuando el usuario establece la hora, el cuadro de diálogo se cierra y un controlador actualiza un TextView
en la pantalla Actividad con la hora seleccionada.
Requisitos
La aplicación de ejemplo de esta guía tiene como destino Android 4.1 (nivel de API 16) o superior, pero se puede usar con Android 3.0 (nivel de API 11 o superior). Es posible admitir versiones anteriores de Android con la adición de la biblioteca de soporte técnico de Android v4 al proyecto y algunos cambios de código.
Uso de TimePicker
En este ejemplo se extiende DialogFragment
; la implementación de subclase de DialogFragment
(denominado TimePickerFragment
a continuación) hospeda y muestra un TimePickerDialog
. Cuando se inicia la aplicación de ejemplo por primera vez, muestra un botón SELECCIONAR HORA situado encima de un TextView
que se usará para mostrar la hora seleccionada:
Al hacer clic en el botón SELECCIONAR HORA, la aplicación de ejemplo inicia TimePickerDialog
como se muestra en esta captura de pantalla:
En TimePickerDialog
, seleccionar una hora y hacer clic en el botón Aceptar hace que TimePickerDialog
invoque el método IOnTimeSetListener.OnTimeSet.
Esta interfaz se implementa mediante el DialogFragment
de hospedaje (TimePickerFragment
, descrito a continuación). Al hacer clic en el botón Cancelar, el fragmento y el cuadro de diálogo se descartan.
DialogFragment
devuelve la hora seleccionada a la actividad de hospedaje de una de estas tres maneras:
Invocar un método o establecer una propiedad: la actividad puede proporcionar una propiedad o método específicamente para establecer este valor.
Generar un evento: el
DialogFragment
puede definir un evento que se generará cuando se invoqueOnTimeSet
.Usar una
Action
: elDialogFragment
puede invocar unaAction<DateTime>
para mostrar la fecha en la actividad. La actividad proporcionará laAction<DateTime
al crear una instancia delDialogFragment
.
Este ejemplo usará la tercera técnica, que requiere que la actividad proporcione un controlador de Action<DateTime>
al DialogFragment
.
Inicio de un proyecto de aplicación
Inicie un nuevo proyecto de Android llamado TimePickerDemo (si no está familiarizado con la creación de proyectos de Xamarin.Android, consulte Hello, Android para aprender a crear un proyecto).
Edite Resources/layout/Main.axml y reemplace su contenido por el siguiente XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:padding="16dp">
<Button
android:id="@+id/select_button"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="PICK TIME"
android:textSize="20dp" />
<TextView
android:id="@+id/time_display"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingTop="22dp"
android:text="Picked time will be displayed here"
android:textSize="24dp" />
</LinearLayout>
Se trata de un elemento LinearLayout básico con un elemento TextView que muestra la hora y un botón que abre TimePickerDialog
. Tenga en cuenta que este diseño usa cadenas y dimensiones codificadas de forma rígida para que la aplicación sea más sencilla y fácil de entender; una aplicación de producción normalmente usa recursos para estos valores (como se puede ver en el ejemplo de código de DatePicker).
Edite MainActivity.cs y reemplace el contenido por el código siguiente:
using Android.App;
using Android.Widget;
using Android.OS;
using System;
using Android.Util;
using Android.Text.Format;
namespace TimePickerDemo
{
[Activity(Label = "TimePickerDemo", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
TextView timeDisplay;
Button timeSelectButton;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
timeDisplay = FindViewById<TextView>(Resource.Id.time_display);
timeSelectButton = FindViewById<Button>(Resource.Id.select_button);
}
}
}
Al compilar y ejecutar este ejemplo, debería ver una pantalla inicial similar a la siguiente captura de pantalla:
Al hacer clic en el botón SELECCIONAR HORA, no sucede nada porque DialogFragment
todavía no se ha implementado para mostrar TimePicker
.
El paso siguiente consiste en crear este DialogFragment
.
Extensión de DialogFragment
Para ampliar DialogFragment
para usarlo con TimePicker
, es necesario crear una subclase derivada de DialogFragment
y que implementa TimePickerDialog.IOnTimeSetListener
. Agregue la siguiente clase a MainActivity.cs:
public class TimePickerFragment : DialogFragment, TimePickerDialog.IOnTimeSetListener
{
public static readonly string TAG = "MyTimePickerFragment";
Action<DateTime> timeSelectedHandler = delegate { };
public static TimePickerFragment NewInstance(Action<DateTime> onTimeSelected)
{
TimePickerFragment frag = new TimePickerFragment();
frag.timeSelectedHandler = onTimeSelected;
return frag;
}
public override Dialog OnCreateDialog (Bundle savedInstanceState)
{
DateTime currentTime = DateTime.Now;
bool is24HourFormat = DateFormat.Is24HourFormat(Activity);
TimePickerDialog dialog = new TimePickerDialog
(Activity, this, currentTime.Hour, currentTime.Minute, is24HourFormat);
return dialog;
}
public void OnTimeSet(TimePicker view, int hourOfDay, int minute)
{
DateTime currentTime = DateTime.Now;
DateTime selectedTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hourOfDay, minute, 0);
Log.Debug(TAG, selectedTime.ToLongTimeString());
timeSelectedHandler (selectedTime);
}
}
Esta clase TimePickerFragment
se divide en partes más pequeñas y se explica en la sección siguiente.
Implementación de DialogFragment
TimePickerFragment
implementa varios métodos: un Factory Method, un método de creación de instancias de diálogo y el método de controlador OnTimeSet
requerido por TimePickerDialog.IOnTimeSetListener
.
El objeto
TimePickerFragment
es una subclase deDialogFragment
. También implementa la interfazTimePickerDialog.IOnTimeSetListener
(es decir, proporciona el métodoOnTimeSet
necesario):public class TimePickerFragment : DialogFragment, TimePickerDialog.IOnTimeSetListener
TAG
se inicializa con fines de registro (MyTimePickerFragment se puede cambiar a cualquier cadena que quiera usar). La accióntimeSelectedHandler
se inicializa en un delegado vacío para evitar excepciones de referencia nula:public static readonly string TAG = "MyTimePickerFragment"; Action<DateTime> timeSelectedHandler = delegate { };
Se llama al Factory Method
NewInstance
para crear una instancia nueva deTimePickerFragment
. Este método toma un controladorAction<DateTime>
que se invoca cuando el usuario hace clic en el botón Aceptar en elTimePickerDialog
:public static TimePickerFragment NewInstance(Action<DateTime> onTimeSelected) { TimePickerFragment frag = new TimePickerFragment(); frag.timeSelectedHandler = onTimeSelected; return frag; }
Cuando se va a mostrar el fragmento, Android llama al método
DialogFragment
OnCreateDialog. Este método crea un nuevo objetoTimePickerDialog
y lo inicializa con la actividad, el objeto de devolución de llamada (que es la instancia actual deTimePickerFragment
) y la hora actual:public override Dialog OnCreateDialog (Bundle savedInstanceState) { DateTime currentTime = DateTime.Now; bool is24HourFormat = DateFormat.Is24HourFormat(Activity); TimePickerDialog dialog = new TimePickerDialog (Activity, this, currentTime.Hour, currentTime.Minute, is24HourFormat); return dialog; }
Cuando el usuario cambia la configuración de hora en el cuadro de diálogo
TimePicker
, se invoca el métodoOnTimeSet
.OnTimeSet
crea un objetoDateTime
con la fecha actual y combina la hora (hora y minuto) seleccionada por el usuario:public void OnTimeSet(TimePicker view, int hourOfDay, int minute) { DateTime currentTime = DateTime.Now; DateTime selectedTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hourOfDay, minute, 0);
Este objeto
DateTime
se pasa altimeSelectedHandler
que se registra con el objetoTimePickerFragment
en la hora de creación.OnTimeSet
invoca este controlador para actualizar la visualización de la hora de la actividad a la hora seleccionada (este controlador se implementa en la sección siguiente):timeSelectedHandler (selectedTime);
Visualización de TimePickerFragment
Ahora que DialogFragment
se ha implementado, es el momento de crear una instancia de DialogFragment
mediante el Factory Method NewInstance
y mostrarlo invocando DialogFragment.Show:
Agregue el método siguiente a MainActivity
:
void TimeSelectOnClick (object sender, EventArgs eventArgs)
{
TimePickerFragment frag = TimePickerFragment.NewInstance (
delegate (DateTime time)
{
timeDisplay.Text = time.ToShortTimeString();
});
frag.Show(FragmentManager, TimePickerFragment.TAG);
}
Después de que TimeSelectOnClick
cree una instancia de TimePickerFragment
, crea y pasa un delegado para un método anónimo que actualiza la visualización de la hora de la actividad con el valor de tiempo que se ha pasado. Por último, inicia el fragmento de diálogo TimePicker
(a través de DialogFragment.Show
) para mostrar TimePicker
al usuario.
Al final del método OnCreate
, agregue la siguiente línea para adjuntar el controlador de eventos al botón SELECCIONAR HORA que inicia el cuadro de diálogo:
timeSelectButton.Click += TimeSelectOnClick;
Cuando se haga clic en el botón SELECCIONAR HORA, se invocará TimeSelectOnClick
para mostrar el fragmento de diálogo TimePicker
al usuario.
¡Inténtelo!
Compile y ejecute la aplicación. Al hacer clic en el botón SELECCIONAR HORA, se muestra TimePickerDialog
en el formato de hora predeterminado para la actividad (en este caso, el modo a. m./p. m. de 12 horas):
Al hacer clic en Aceptar en el cuadro de diálogo TimePicker
, el controlador actualiza el elemento TextView
de la actividad con la hora elegida y, a continuación, se cierra:
A continuación, agregue la siguiente línea de código a OnCreateDialog
inmediatamente después de que is24HourFormat
se declare e inicialice:
is24HourFormat = true;
Este cambio hace que la marca pasada al constructor TimePickerDialog
sea true
para que se use el modo de 24 horas en lugar del formato de hora de la actividad de hospedaje. Al compilar y ejecutar la aplicación de nuevo, haga clic en el botón SELECCIONAR HORA; el cuadro de diálogo TimePicker
se muestra ahora en formato de 24 horas:
Dado que el controlador llama a DateTime.ToShortTimeString para imprimir la hora en el elemento TextView
de la actividad, la hora todavía se imprime en el formato predeterminado de 12 horas a. m./p. m.
Resumen
En este artículo, se ha explicado cómo mostrar un widget TimePicker
como un cuadro de diálogo modal emergente desde una actividad de Android. Se proporcionó una implementación de DialogFragment
de ejemplo y explicó la interfaz IOnTimeSetListener
. En este ejemplo, también se ha mostrado cómo DialogFragment
puede interactuar con la actividad de hospedaje para mostrar la hora seleccionada.