Okna wyboru godziny

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

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

Podstawowy przykład

Najprostszym sposobem na utworzenie okna dla selektora czasu jest utworzenie funkcji kompozycyjnej, która implementuje AlertDialog. Poniższy fragment kodu przedstawia przykład stosunkowo prostego okna dialogowego, które korzysta z tego podejścia:

@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 elementy tego fragmentu kodu:

  1. Funkcja kompozycyjna DialWithDialogExample opakowuje TimePicker w oknie dialogowym.
  2. TimePickerDialog to niestandardowy element kompozycyjny, który tworzy AlertDialog z tymi parametrami:
    • onDismiss: funkcja wywoływana, gdy użytkownik zamyka 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 „Zamknij”.
    • Przycisk potwierdzenia z etykietą „OK”.
    • Treść selektora czasu przekazana jako parametr text.
  4. Funkcja DialWithDialogExample inicjuje zmienną TimePickerState z bieżącą godziną i przekazuje ją do funkcji TimePicker i onConfirm.
Selektor czasu w komponencie AlertDialog, który zawiera tytuł, przełącznik trybu oraz przyciski odrzucenia i potwierdzenia.
Rysunek 1. A time picker in an AlertDialog.

Przykład zaawansowany

Ten fragment kodu pokazuje zaawansowaną implementację dostosowywanego okna wyboru godziny 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 elementy tego fragmentu kodu:

  1. Funkcja kompozycyjna AdvancedTimePickerExample tworzy okno selektora czasu, które można dostosować.
  2. Używa funkcji kompozycyjnej Dialog, która zapewnia większą elastyczność niż AlertDialog.
  3. Okno zawiera konfigurowalny tytuł i przycisk przełączania, który umożliwia przełączanie się między trybami wybierania i wprowadzania.
  4. Surface stosuje kształt i wysokość do okna, a IntrinsicSize.Min do szerokości i wysokości.
  5. Układy Column i Row zawierają komponenty struktury okna.
  6. W przykładzie tryb selektora jest śledzony za pomocą właściwości showDial.
    • IconButton przełącza się między trybami, odpowiednio aktualizując ikonę.
    • Zawartość okna dialogowego przełącza się między TimePicker a TimeInput w zależności od stanu showDial.

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

Implementacja wygląda tak:

Selektor godziny w niestandardowym oknie dialogowym, które zawiera tytuł, przełącznik trybu oraz przyciski odrzucenia i potwierdzenia.
Rysunek 2. Selektor godziny w niestandardowym oknie.

Dodatkowe materiały