Selektory dat

Selektory dat umożliwiają użytkownikom wybranie daty, zakresu dat lub obu tych elementów. Firma korzysta z okna kalendarza lub wprowadzania tekstu, aby umożliwić użytkownikom wybranie dat.

Typy

Istnieją 3 rodzaje selektorów dat:

  • Zadokowany: pojawia się w tekście w układzie. Jest odpowiednia dla kompaktowych urządzeń w których specjalne okno może być uciążliwe.
  • Okno modalne: wyświetla się jako okno nakładające się na zawartość aplikacji. Zapewnia to wyczyść zaznaczenie daty.
  • Modalny element wejściowy: łączy pole tekstowe z modalnym selektorem daty.

Możesz zaimplementować te selektory dat w swojej aplikacji za pomocą tych komponentów:

  • DatePicker: ogólna funkcja kompozycyjna dla selektora daty. To, czy kontener jest dokowany czy modelowy, zależy od używanego kontenera.
  • DatePickerDialog: kontener dla modalnych selektorów daty.
  • DateRangePicker: w przypadku każdego selektora daty, w którym użytkownik może wybrać zakresu z datą rozpoczęcia i zakończenia.
.

Region

Kluczowym parametrem, który mają wspólny różne komponenty selektora daty, jest state, który przyjmuje obiekt DatePickerState lub DateRangePickerState. Ich właściwości rejestrują informacje o wybraniu przez użytkownika opcji za pomocą selektora daty, np. bieżącej wybranej daty.

Więcej informacji o tym, jak korzystać z wybranej daty, znajdziesz w sekcji Używanie wybranej daty.

Przypięty selektor daty

W tym przykładzie jest pole tekstowe, które prosi użytkownika o podanie daty urodzenia. Gdy użytkownik kliknie ikonę kalendarza w polu, pod polem wprowadzania otworzy się przypięty selektor daty.

@Composable
fun DatePickerDocked() {
    var showDatePicker by remember { mutableStateOf(false) }
    val datePickerState = rememberDatePickerState()
    val selectedDate = datePickerState.selectedDateMillis?.let {
        convertMillisToDate(it)
    } ?: ""

    Box(
        modifier = Modifier.fillMaxWidth()
    ) {
        OutlinedTextField(
            value = selectedDate,
            onValueChange = { },
            label = { Text("DOB") },
            readOnly = true,
            trailingIcon = {
                IconButton(onClick = { showDatePicker = !showDatePicker }) {
                    Icon(
                        imageVector = Icons.Default.DateRange,
                        contentDescription = "Select date"
                    )
                }
            },
            modifier = Modifier
                .fillMaxWidth()
                .height(64.dp)
        )

        if (showDatePicker) {
            Popup(
                onDismissRequest = { showDatePicker = false },
                alignment = Alignment.TopStart
            ) {
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .offset(y = 64.dp)
                        .shadow(elevation = 4.dp)
                        .background(MaterialTheme.colorScheme.surface)
                        .padding(16.dp)
                ) {
                    DatePicker(
                        state = datePickerState,
                        showModeToggle = false
                    )
                }
            }
        }
    }
}

@Composable
fun DatePickerFieldToModal(modifier: Modifier = Modifier) {
    var selectedDate by remember { mutableStateOf<Long?>(null) }
    var showModal by remember { mutableStateOf(false) }

    OutlinedTextField(
        value = selectedDate?.let { convertMillisToDate(it) } ?: "",
        onValueChange = { },
        label = { Text("DOB") },
        placeholder = { Text("MM/DD/YYYY") },
        trailingIcon = {
            Icon(Icons.Default.DateRange, contentDescription = "Select date")
        },
        modifier = modifier
            .fillMaxWidth()
            .pointerInput(selectedDate) {
                awaitEachGesture {
                    // Modifier.clickable doesn't work for text fields, so we use Modifier.pointerInput
                    // in the Initial pass to observe events before the text field consumes them
                    // in the Main pass.
                    awaitFirstDown(pass = PointerEventPass.Initial)
                    val upEvent = waitForUpOrCancellation(pass = PointerEventPass.Initial)
                    if (upEvent != null) {
                        showModal = true
                    }
                }
            }
    )

    if (showModal) {
        DatePickerModal(
            onDateSelected = { selectedDate = it },
            onDismiss = { showModal = false }
        )
    }
}

fun convertMillisToDate(millis: Long): String {
    val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault())
    return formatter.format(Date(millis))
}

Najważniejsze informacje o kodzie

  • Selektor dat pojawia się, gdy użytkownik kliknie IconButton.
    • Przycisk ikony służy jako argument funkcji OutlinedTextField trailingIcon.
    • Zmienna stanu showDatePicker kontroluje widoczność zadokowanego selektora daty.
  • Kontener selektora dat to funkcja kompozycyjna Popup, która nakłada treści bez wpływu na układ innych elementów.
  • selectedDate rejestruje wartość wybranej daty z DatePickerState obiekt i formatuje go za pomocą convertMillisToDate .
  • Wybrana data pojawi się w polu tekstowym.
  • Zadokowany selektor daty znajduje się pod polem tekstowym za pomocą komponentu offset modyfikator.
  • Box jest używany jako kontener główny, dzięki czemu tekst jest poprawnie nałożony na warstwy i selektor daty.

Wyniki

Po kliknięciu ikony kalendarza ta implementacja wygląda tak:

Przykład zadokowanego selektora daty.
Rysunek 1. Przypięty selektor daty.

Modalny selektor daty wyświetla okno pływające po ekranie. Aby go zaimplementować, utwórz DatePickerDialog i przenieś go do DatePicker.

@Composable
fun DatePickerModal(
    onDateSelected: (Long?) -> Unit,
    onDismiss: () -> Unit
) {
    val datePickerState = rememberDatePickerState()

    DatePickerDialog(
        onDismissRequest = onDismiss,
        confirmButton = {
            TextButton(onClick = {
                onDateSelected(datePickerState.selectedDateMillis)
                onDismiss()
            }) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    ) {
        DatePicker(state = datePickerState)
    }
}

  • Funkcja kompozycyjna DatePickerModal wyświetla modalny selektor daty.
  • Wyrażenie lambda onDateSelected jest wykonywane, gdy użytkownik wybierze datę.
    • Ujawnia wybraną datę dla nadrzędnej funkcji kompozycyjnej.
  • Wyrażenie lambda onDismiss jest wykonywane, gdy użytkownik zamknie okno.

Wyniki

Implementacja wygląda tak:

Przykład modalnego selektora daty.
Rysunek 2. Modalny selektor daty.

Selektor daty modalnej

Tryb wyboru daty z polami wejściowymi wyświetla okno modalne, które unosi się nad ekranem i pozwala użytkownikowi na podanie daty.

@Composable
fun DatePickerModalInput(
    onDateSelected: (Long?) -> Unit,
    onDismiss: () -> Unit
) {
    val datePickerState = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)

    DatePickerDialog(
        onDismissRequest = onDismiss,
        confirmButton = {
            TextButton(onClick = {
                onDateSelected(datePickerState.selectedDateMillis)
                onDismiss()
            }) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    ) {
        DatePicker(state = datePickerState)
    }
}

Przypomina to przykład modalnego selektora daty. Podstawowy różnica jest taka:

  • Parametr initialDisplayMode ustawia początkowy tryb wyświetlania na DisplayMode.Input.
.
Modalny selektor daty z pola wejściowego.
Rys. 3. Modalny selektor daty z polami wejściowymi.

Selektor dat z zakresem

Możesz utworzyć selektor daty, który umożliwi użytkownikowi wybór zakresu od daty rozpoczęcia i datę zakończenia. Aby to zrobić, użyj DateRangePicker.

Użycie pola DateRangePicker jest zasadniczo takie samo jak pola DatePicker. Możesz go użyć jako dokowanego selektora jako elementu podrzędnego PopUp lub jako modalnego selektora i przekazać go do DatePickerDialog. Główna różnica to używasz DateRangePickerState zamiast DatePickerState.

Ten fragment kodu pokazuje, jak utworzyć modalny selektor daty z zakresem:

@Composable
fun DateRangePickerModal(
    onDateRangeSelected: (Pair<Long?, Long?>) -> Unit,
    onDismiss: () -> Unit
) {
    val dateRangePickerState = rememberDateRangePickerState()

    DatePickerDialog(
        onDismissRequest = onDismiss,
        confirmButton = {
            TextButton(
                onClick = {
                    onDateRangeSelected(
                        Pair(
                            dateRangePickerState.selectedStartDateMillis,
                            dateRangePickerState.selectedEndDateMillis
                        )
                    )
                    onDismiss()
                }
            ) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    ) {
        DateRangePicker(
            state = dateRangePickerState,
            title = {
                Text(
                    text = "Select date range"
                )
            },
            showModeToggle = false,
            modifier = Modifier
                .fillMaxWidth()
                .height(500.dp)
                .padding(16.dp)
        )
    }
}

Najważniejsze informacje o kodzie

  • Parametr onDateRangeSelected to funkcja zwracająca wartość Pair<Long?, Long?>, która reprezentuje wybrane daty rozpoczęcia i zakończenia. Daje to elementom nadrzędnym dostęp do wybranego zakresu.
  • rememberDateRangePickerState() tworzy stan dla selektora zakresu dat.
  • Element DatePickerDialog tworzy modalny kontener dialogu.
  • W obiekcie onClick w przycisku potwierdzenia obiekt onDateRangeSelected przekazuje wybrany zakres do nadrzędnego elementu składanego.
  • Element kompozytywny DateRangePicker służy jako treść okna.

Wyniki

Ta implementacja wygląda tak:

Przykład selektora zakresu dat w oknie modalnym
Rysunek 4. Wyświetlany modalnie selektor daty z wybranym zakresem.

Użyj wybranej daty

Aby zarejestrować wybraną datę, śledź ją w komponencie nadrzędnym jako Long oraz przekazać wartość do funkcji DatePicker w onDateSelected. Poniżej znajduje się fragment kodu, który to demonstruje, ale pełną implementację znajdziesz w oficjalnej aplikacji snippetów.

// ...
    var selectedDate by remember { mutableStateOf<Long?>(null) }
// ...
        if (selectedDate != null) {
            val date = Date(selectedDate!!)
            val formattedDate = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()).format(date)
            Text("Selected date: $formattedDate")
        } else {
            Text("No date selected")
        }
// ...
        DatePickerModal(
            onDateSelected = {
                selectedDate = it
                showModal = false
            },
            onDismiss = { showModal = false }
        )
    }
// ...

Zasadniczo to samo dotyczy selektorów zakresu dat, ale musisz użyj Pair<Long?, Long?> lub klasy danych do przechwytywania wartości początkowej i końcowej.

Zobacz również