Seletores de data

Os seletores de data permitem que os usuários selecionem uma data, um período ou ambos. Eles usam um caixa de diálogo da agenda ou entrada de texto para que os usuários selecionem datas.

Tipos

Há três tipos de seletores de data:

  • Na base: aparece inline no layout. Ele é adequado para aplicativos layouts em que um diálogo dedicado pode parecer invasivo.
  • Modal: aparece como uma caixa de diálogo sobreposta ao conteúdo do app. Isso oferece uma foco claro na seleção da data.
  • Entrada modal: combina um campo de texto com um seletor de data modal.

Implemente esses seletores de data no seu app usando o seguinte que podem ser compostos:

  • DatePicker: elemento combinável geral para um seletor de data. O contêiner que você O uso determina se ele está na base ou se é um modelo.
  • DatePickerDialog: o contêiner da data de entrada modal e modal. seletores.
  • DateRangePicker: para qualquer seletor de data em que o usuário possa escolher uma com uma data de início e de término.
.

Estado

O principal parâmetro que os diferentes elementos combináveis do seletor de data têm em comum é state, que usa um DatePickerState ou DateRangePickerState. As propriedades deles capturam informações sobre a seleção do usuário usando o seletor de data, como a data selecionada no momento.

Para mais informações sobre como você pode usar a data selecionada, consulte a seção Usar seção de data selecionada.

Seletor de data fixo

No exemplo a seguir, há um campo de texto que solicita que o usuário insira a data de nascimento. Quando ele clica no ícone de calendário no campo, ele abre uma seletor de data encaixado abaixo do campo de entrada.

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

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

Pontos principais sobre o código

  • O seletor de data aparece quando o usuário clica no IconButton.
    • O botão do ícone serve como argumento para o OutlinedTextField parâmetro trailingIcon.
    • A variável de estado showDatePicker controla a visibilidade do seletor de data na base.
  • O contêiner do seletor de data é um elemento combinável Popup, que se sobrepõe à do conteúdo sem afetar o layout de outros elementos.
  • selectedDate captura o valor da data selecionada do DatePickerState e o formata usando o convertMillisToDate função.
  • A data selecionada aparece no campo de texto.
  • O seletor de data na base é posicionado abaixo do campo de texto usando um offset .
  • Uma Box é usada como o contêiner raiz para permitir a criação adequada de camadas do texto. e o seletor de data.

Resultados

Depois de clicar no ícone do calendário, essa implementação aparece da seguinte maneira:

Exemplo de seletor de data fixado.
Figura 1. Um seletor de data na base.

Um seletor de data modal mostra uma caixa de diálogo que flutua sobre a tela. Para implementar crie um DatePickerDialog e transmita a ele um 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)
    }
}

  • A função combinável DatePickerModal mostra um seletor de data modal.
  • A expressão lambda onDateSelected é executada quando o usuário seleciona um data.
    • Ele expõe a data selecionada ao elemento combinável pai.
  • A expressão lambda onDismiss é executada quando o usuário dispensa o caixa de diálogo.

Resultados

Essa implementação aparece da seguinte maneira:

Exemplo de seletor de data modal.
Figura 2. Um seletor de data modal.

Seletor de data modal de entrada

Um seletor de data modal com entrada mostra uma caixa de diálogo que flutua sobre a tela e permite que o usuário insira uma data.

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

Isso é muito parecido com o exemplo do seletor de data modal. O principal a diferença é a seguinte:

  • O parâmetro initialDisplayMode define o modo de exibição inicial como DisplayMode.Input.
.
Seletor modal de data com entrada.
Figura 3. Um seletor de data modal com entrada.

Seletor de data com intervalo

É possível criar um seletor de data que permite ao usuário escolher um período entre o início e a data de término. Para fazer isso, use DateRangePicker.

O uso de DateRangePicker é essencialmente o mesmo que DatePicker. Você pode Use-o para um seletor ancorado como filho de PopUp ou como um seletor modal e transmita-o para DatePickerDialog. A principal diferença é use DateRangePickerState em vez de DatePickerState.

O snippet a seguir demonstra como criar um seletor de data modal com uma intervalo:

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

Pontos principais sobre o código

  • O parâmetro onDateRangeSelected é um callback que recebe um Pair<Long?, Long?> que representa as datas de início e término selecionadas. Isso concede ao elemento combinável pai acesso ao intervalo selecionado.
  • rememberDateRangePickerState() cria o estado para o período. seletor.
  • O DatePickerDialog cria um contêiner de caixa de diálogo modal.
  • No gerenciador onClick do botão de confirmação, onDateRangeSelected transmite o intervalo selecionado ao elemento combinável pai.
  • O elemento combinável DateRangePicker serve como o conteúdo da caixa de diálogo.

Resultados

Essa implementação aparece da seguinte maneira:

Exemplo de seletor de data de período modal.
Figura 4. Um seletor de data modal com um período selecionado.

Usar a data selecionada

Para capturar a data selecionada, rastreie-a no elemento combinável pai como um Long. Transmita o valor para DatePicker em onDateSelected. O snippet a seguir demonstra isso, embora você possa ver a implementação completa na página oficial snippets do app.

// ...
    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 }
        )
    }
// ...

Essencialmente, o mesmo se aplica aos seletores de data de período, embora seja necessário use um Pair<Long?, Long?> ou uma classe de dados para capturar os valores inicial e final.

Veja também