Okna wyboru godziny

Selektory czasu często pojawiają się w oknach. Możesz użyć stosunkowo ogólnej i minimalnej implementacji okna lub wdrożyć okno niestandardowe, które daje większą elastyczność.

Więcej informacji o oknach, w tym o tym, jak używać stanu selektora czasu, znajdziesz w przewodniku po selektorach czasu.

Podstawowy przykład

Najprostszym sposobem utworzenia okna dialogowego selektora czasu jest utworzenie funkcji kompozycyjnej, która implementuje interfejs AlertDialog. Poniższy fragment kodu zawiera przykład stosunkowo prostego okna dialogowego, które wykorzystuje to podejście:

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

Zwróć uwagę na najważniejsze kwestie w tym fragmencie kodu:

  1. Funkcja kompozycyjna DialWithDialogExample opakowuje element TimePicker w oknie.
  2. TimePickerDialog to niestandardowy komponent, który tworzy AlertDialog z tymi parametrami:
    • onDismiss: funkcja wywoływana, gdy użytkownik zamknie okno (za pomocą przycisku zamykania lub przycisku Wstecz).
    • onConfirm: funkcja wywoływana, gdy użytkownik kliknie przycisk „OK”.
    • content: funkcja kompozycyjna, która wyświetla selektor czasu w oknie.
  3. AlertDialog obejmuje:
    • Przycisk zamykania z etykietą „Zamknij”.
    • Przycisk potwierdzenia z etykietą „OK”.
    • Treść selektora czasu przekazana jako parametr text.
  4. Funkcja DialWithDialogExample inicjuje funkcję TimePickerState z bieżącym czasem i przekazuje ją do funkcji TimePickeronConfirm.
Selektor czasu w oknie AlertDialog, który zawiera tytuł, przełącznik trybu oraz przyciski odrzucania i potwierdzania.
Rysunek 1. Selektor czasu w oknie AlertDialog.

Zaawansowany przykład

Ten fragment kodu przedstawia zaawansowaną implementację konfigurowalnego okna wyboru czasu w 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") }
                }
            }
        }
    }
}

Zwróć uwagę na najważniejsze kwestie w tym fragmencie kodu:

  1. Funkcja kompozycyjna AdvancedTimePickerExample tworzy konfigurowalne okno wyboru czasu.
  2. Używa funkcji Dialog, która zapewnia większą elastyczność niż AlertDialog.
  3. Okno zawiera dostosowywany tytuł i przycisk przełączania między trybami wybierania i wpisywania.
  4. Surface stosuje kształt i wysokość do okna, przy czym IntrinsicSize.Min dotyczy zarówno szerokości, jak i wysokości.
  5. Układy ColumnRow zawierają komponenty struktury okna.
  6. W przykładzie śledzimy tryb selektora za pomocą parametru showDial.
    • Ikona IconButton przełącza tryby i odpowiednio się zmienia.
    • Zawartość okna dialogowego przełącza się między TimePickerTimeInput w zależności od stanu showDial.

Ta zaawansowana implementacja zapewnia wysoce konfigurowalne i wielokrotnego użytku okno wyboru czasu, które można dostosować do różnych przypadków użycia w aplikacji.

Ta implementacja wygląda tak:

Selektor czasu w oknie niestandardowym, który zawiera tytuł, przełącznik trybu oraz przyciski odrzucania i potwierdzania.
Rysunek 2. Okno wyboru godziny w niestandardowym oknie.

Dodatkowe materiały