Diálogos para selectores de hora

Los selectores de horarios suelen aparecer en los diálogos. Puedes usar una implementación relativamente genérica y mínima de un diálogo, o bien implementar un diálogo personalizado con más flexibilidad.

Para obtener más información sobre los diálogos en general, incluido cómo usar el estado del selector de hora, consulta la guía de selectores de hora.

Ejemplo básico

La forma más directa de crear un diálogo para tu selector de hora es crear un elemento componible que implemente AlertDialog. En el siguiente fragmento, se proporciona un ejemplo de un diálogo relativamente mínimo con este enfoque:

@Composable
fun DialWithDialogExample(
    onConfirm: (TimePickerState) -> Unit,
    onDismiss: () -> Unit,
) {
    val currentTime = Calendar.getInstance()

    val timePickerState = rememberTimePickerState(
        initialHour = currentTime.get(Calendar.HOUR_OF_DAY),
        initialMinute = currentTime.get(Calendar.MINUTE),
        is24Hour = true,
    )

    TimePickerDialog(
        onDismiss = { onDismiss() },
        onConfirm = { onConfirm(timePickerState) }
    ) {
        TimePicker(
            state = timePickerState,
        )
    }
}

@Composable
fun TimePickerDialog(
    onDismiss: () -> Unit,
    onConfirm: () -> Unit,
    content: @Composable () -> Unit
) {
    AlertDialog(
        onDismissRequest = onDismiss,
        dismissButton = {
            TextButton(onClick = { onDismiss() }) {
                Text("Dismiss")
            }
        },
        confirmButton = {
            TextButton(onClick = { onConfirm() }) {
                Text("OK")
            }
        },
        text = { content() }
    )
}

Ten en cuenta los puntos clave de este fragmento:

  1. El elemento componible DialWithDialogExample une TimePicker en un diálogo.
  2. TimePickerDialog es un elemento componible personalizado que crea un AlertDialog con los siguientes parámetros:
    • onDismiss: Es una función a la que se llama cuando el usuario descarta el diálogo (a través del botón de descarte o el gesto atrás de navegación).
    • onConfirm: Es una función a la que se llama cuando el usuario hace clic en el botón "Aceptar".
    • content: Es un elemento componible que muestra el selector de hora en el diálogo.
  3. AlertDialog incluye lo siguiente:
    • Un botón para descartar con la etiqueta “Descartar”.
    • Un botón de confirmación con la etiqueta “OK”.
    • El contenido del selector de hora que se pasa como el parámetro text
  4. DialWithDialogExample inicializa TimePickerState con la hora actual y la pasa a TimePicker y a la función onConfirm.
Un selector de hora en un AlertDialog que implementa un título, un botón de activación de modo y botones de descarte y confirmación.
Figura 1: Un selector de hora en un AlertDialog.

Ejemplo avanzado

En este fragmento, se muestra una implementación avanzada de un diálogo de selector de hora personalizable en Jetpack Compose.

@Composable
fun AdvancedTimePickerExample(
    onConfirm: (TimePickerState) -> Unit,
    onDismiss: () -> Unit,
) {

    val currentTime = Calendar.getInstance()

    val timePickerState = rememberTimePickerState(
        initialHour = currentTime.get(Calendar.HOUR_OF_DAY),
        initialMinute = currentTime.get(Calendar.MINUTE),
        is24Hour = true,
    )

    /** Determines whether the time picker is dial or input */
    var showDial by remember { mutableStateOf(true) }

    /** The icon used for the icon button that switches from dial to input */
    val toggleIcon = if (showDial) {
        Icons.Filled.EditCalendar
    } else {
        Icons.Filled.AccessTime
    }

    AdvancedTimePickerDialog(
        onDismiss = { onDismiss() },
        onConfirm = { onConfirm(timePickerState) },
        toggle = {
            IconButton(onClick = { showDial = !showDial }) {
                Icon(
                    imageVector = toggleIcon,
                    contentDescription = "Time picker type toggle",
                )
            }
        },
    ) {
        if (showDial) {
            TimePicker(
                state = timePickerState,
            )
        } else {
            TimeInput(
                state = timePickerState,
            )
        }
    }
}

@Composable
fun AdvancedTimePickerDialog(
    title: String = "Select Time",
    onDismiss: () -> Unit,
    onConfirm: () -> Unit,
    toggle: @Composable () -> Unit = {},
    content: @Composable () -> Unit,
) {
    Dialog(
        onDismissRequest = onDismiss,
        properties = DialogProperties(usePlatformDefaultWidth = false),
    ) {
        Surface(
            shape = MaterialTheme.shapes.extraLarge,
            tonalElevation = 6.dp,
            modifier =
            Modifier
                .width(IntrinsicSize.Min)
                .height(IntrinsicSize.Min)
                .background(
                    shape = MaterialTheme.shapes.extraLarge,
                    color = MaterialTheme.colorScheme.surface
                ),
        ) {
            Column(
                modifier = Modifier.padding(24.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(bottom = 20.dp),
                    text = title,
                    style = MaterialTheme.typography.labelMedium
                )
                content()
                Row(
                    modifier = Modifier
                        .height(40.dp)
                        .fillMaxWidth()
                ) {
                    toggle()
                    Spacer(modifier = Modifier.weight(1f))
                    TextButton(onClick = onDismiss) { Text("Cancel") }
                    TextButton(onClick = onConfirm) { Text("OK") }
                }
            }
        }
    }
}

Ten en cuenta los puntos clave de este fragmento:

  1. El elemento componible AdvancedTimePickerExample crea un diálogo de selector de hora personalizable.
  2. Usa un elemento Dialog componible para obtener más flexibilidad que AlertDialog.
  3. El diálogo incluye un título personalizable y un botón de activación para cambiar entre los modos de marcado y de entrada.
  4. Surface aplica forma y elevación al diálogo, con IntrinsicSize.Min para el ancho y la altura.
  5. El diseño Column y Row proporciona los componentes de la estructura del diálogo.
  6. En el ejemplo, se realiza un seguimiento del modo de selección usando showDial.
    • Un IconButton alterna entre los modos y actualiza el ícono según corresponda.
    • El contenido del diálogo cambia entre TimePicker y TimeInput según el estado showDial.

Esta implementación avanzada proporciona un diálogo de selección de tiempo altamente personalizable y reutilizable que puede adaptarse a diferentes casos de uso en tu app.

Esta implementación aparece de la siguiente manera:

Un selector de hora en un diálogo personalizado que implementa un título, un botón de activación de modo y botones para descartar y confirmar.
Figura 2: Un selector de hora en un diálogo personalizado

Recursos adicionales