Okna wyboru godziny

Selektory czasu często pojawiają się w dialogach. Możesz użyć stosunkowo ogólnego i minimalnego dialogu lub wdrożyć niestandardowy dialog o większej elastyczności.

Więcej informacji o dialogach, w tym o używaniu stanu selektora czasu, znajdziesz w przewodniku po selektorze czasu.

Przykład podstawowy

Najprostszym sposobem utworzenia okna dialogowego selektora czasu jest utworzenie komponentu, który implementuje AlertDialog. Ten fragment kodu przedstawia przykład stosunkowo krótkiego dialogu:

@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 punkty w tym fragmencie kodu:

  1. Składanka DialWithDialogExample zawiera komponent 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 zamknięcia lub przycisku Wstecz).
    • onConfirm: funkcja wywoływana, gdy użytkownik kliknie przycisk „OK”.
    • content: element składany, który wyświetla selektor czasu w oknie.
  3. AlertDialog obejmuje:
    • Przycisk zamknięcia z nazwą „Zamknij”.
    • przycisk potwierdzenia z nazwą „OK”.
    • Treść selektora czasu przekazana jako parametr text.
  4. Funkcja DialWithDialogExample inicjalizuje zmienną TimePickerState bieżącym czasem i przekazuje go do funkcji TimePicker oraz onConfirm.
Selektor czasu w dialogu AlertDialog, który zawiera tytuł, przełącznik trybu oraz przyciski odrzucania i potwierdzania.
Rysunek 1. Wybór godziny w oknie AlertDialog.

Przykład zaawansowany

Ten fragment kodu demonstruje zaawansowane wdrożenie dostosowywalnego 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 punkty w tym fragmencie kodu:

  1. Komponent AdvancedTimePickerExample tworzy dostosowywalny selektor czasu.
  2. Używa ona komponentu Dialog, który zapewnia większą elastyczność niż AlertDialog.
  3. Okno zawiera tytuł, który można dostosować, oraz przełącznik umożliwiający przełączanie się między trybem wybierania a wprowadzania.
  4. Surface stosuje kształt i wypukłość do dialogu, przy czym IntrinsicSize.Min dotyczy zarówno szerokości, jak i wysokości.
  5. Układy ColumnRow udostępniają komponenty struktury okna.
  6. W tym przykładzie używany jest parametr showDial do śledzenia trybu selektora.
    • IconButton przełącza się między trybami, odpowiednio aktualizując ikonę.
    • Treść dialogu przełącza się między TimePickerTimeInput w zależności od stanu showDial.

Ta zaawansowana implementacja zapewnia wysoce konfigurowalny i możliwy do ponownego użycia interfejs wyboru czasu, który można dostosować do różnych zastosowań w aplikacji.

Ta implementacja wygląda tak:

Selektor czasu w oknie dialogowym z tytułem, przełącznikiem trybu oraz przyciskami odrzucania i potwierdzania.
Rysunek 2. Wybór godziny w oknie niestandardowym.

Dodatkowe materiały