Os seletores de data permitem que os usuários selecionem uma data, um período ou ambos. Eles usam uma caixa de diálogo de calendário ou entrada de texto para permitir que os usuários selecionem datas.
Tipos
Há três tipos de seletores de data:
- Anexado: aparece em linha no layout. É adequado para layouts compactos em que uma caixa de diálogo dedicada pode parecer intrusiva.
- Modal: aparece como uma caixa de diálogo sobrepondo o conteúdo do app. Isso oferece um foco claro na seleção de datas.
- Entrada modal: combina um campo de texto com um seletor de data modal.
É possível implementar esses seletores de data no seu app usando os seguintes elementos combináveis:
DatePicker: elemento combinável geral para um seletor de data. O contêiner usado determina se ele está anexado ou é um modelo.DatePickerDialog: o contêiner para seletores de data modais e de entrada modal.DateRangePicker: para qualquer seletor de data em que o usuário possa selecionar um período com uma data de início e de término.
Estado
O parâmetro principal que os diferentes elementos combináveis do seletor de data compartilham é
state, que usa um objeto 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 atual.
Para mais informações sobre como usar a data selecionada, consulte a seção Usar a data selecionada.
Seletor de data anexado
No exemplo a seguir, há uma caixa de texto que solicita ao usuário que insira a data de nascimento. Quando o usuário clica no ícone de calendário no campo, um seletor de data anexado é aberto 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 ) } } } } } @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)) }
Pontos principais sobre o código
- O seletor de data aparece quando o usuário clica no
IconButton.- O botão de ícone serve como argumento para o parâmetro
trailingIcondoOutlinedTextField. - A variável de estado
showDatePickercontrola a visibilidade do seletor de data anexado.
- O botão de ícone serve como argumento para o parâmetro
- O contêiner do seletor de data é um elemento combinável
Popup, que sobrepõe o conteúdo sem afetar o layout de outros elementos. selectedDatecaptura o valor da data selecionada do objetoDatePickerStatee o formata usando a funçãoconvertMillisToDate.- A data selecionada aparece no campo de texto.
- O seletor de data anexado é posicionado abaixo do campo de texto usando um modificador
offset. - Uma
Boxé usada como o contêiner raiz para permitir a sobreposição adequada do campo de texto e do seletor de data.
Resultados
Depois de clicar no ícone de calendário, essa implementação aparece da seguinte maneira:
Seletor de data modal
Um seletor de data modal mostra uma caixa de diálogo que flutua sobre a tela. Para implementá-lo, crie um DatePickerDialog e transmita 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) } }
Pontos principais sobre o código
- A função combinável
DatePickerModalmostra um seletor de data modal. - A expressão lambda
onDateSelectedé executada quando o usuário seleciona uma data.- Ela expõe a data selecionada ao elemento combinável pai.
- A expressão lambda
onDismissé executada quando o usuário dispensa a caixa de diálogo.
Resultados
Essa implementação aparece da seguinte maneira:
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) } }
Pontos principais sobre o código
Isso é muito parecido com o exemplo de seletor de data modal. A principal diferença é a seguinte:
- O parâmetro
initialDisplayModedefine o modo de exibição inicial comoDisplayMode.Input.
Seletor de data com período
É possível criar um seletor de data que permita ao usuário selecionar um período entre uma data de início e de término. Para fazer isso, use DateRangePicker.
O uso de DateRangePicker é basicamente o mesmo que DatePicker. É possível
usá-lo para um seletor anexado como filho de PopUp ou usá-lo como um
seletor modal e transmiti-lo para DatePickerDialog. A principal diferença é
que você usa DateRangePickerState em vez de DatePickerState.
O snippet a seguir demonstra como criar um seletor de data modal com um período:
@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 umPair<Long?, Long?>que representa as datas de início e de término selecionadas. Isso dá ao elemento combinável pai acesso ao período selecionado. rememberDateRangePickerState()cria o estado para o seletor de período.- O
DatePickerDialogcria um contêiner de caixa de diálogo modal. - No handler
onClickdo botão de confirmação,onDateRangeSelectedtransmite o período selecionado para o elemento combinável pai. - O elemento combinável
DateRangePickerserve como conteúdo da caixa de diálogo.
Resultados
Essa implementação aparece da seguinte maneira:
Usar a data selecionada
Para capturar a data selecionada, rastreie-a no elemento combinável pai como um Long e transmita o valor para o DatePicker em onDateSelected. O snippet a seguir
demonstra isso, mas você pode conferir a implementação completa no app de snippets oficial.
// ... 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 } ) } // ...
Basicamente, o mesmo se aplica aos seletores de data de período, embora seja necessário
usar um Pair<Long?, Long?> ou uma classe de dados para capturar os valores de início e de término.