I selettori della data consentono agli utenti di selezionare una data, un intervallo di date o entrambi. Utilizzano una finestra di dialogo del calendario o un input di testo per consentire agli utenti di selezionare le date.
Tipi
Esistono tre tipi di selettori della data:
- Agganciato: viene visualizzato in linea all'interno del layout. È adatto per layout compatti in cui una finestra di dialogo dedicata potrebbe risultare invadente.
- Modale: viene visualizzata come finestra di dialogo sovrapposta ai contenuti dell'app. Ciò consente di definire con chiarezza la selezione delle date.
- Input modale: combina un campo di testo con un selettore della data modale.
Puoi implementare questi selettori della data nella tua app utilizzando i seguenti composabili:
DatePicker
: composable generico per un selettore della data. Il contenitore che utilizzi determina se è agganciato o modello.DatePickerDialog
: il contenitore per i selettori di data di input sia modali sia modali.DateRangePicker
: per qualsiasi selettore della data in cui l'utente può selezionare un intervallo con una data di inizio e una di fine.
Stato
Il parametro chiave che i diversi composabili del selettore della data hanno in comune è
state
, che accetta un oggetto DatePickerState
o
DateRangePickerState
. Le relative proprietà acquisiscono informazioni sulla selezione dell'utente utilizzando il selettore della data, ad esempio la data selezionata corrente.
Per ulteriori informazioni su come utilizzare la data selezionata, consulta la sezione Utilizzare la data selezionata.
Selettore della data agganciato
Nell'esempio seguente è presente un campo di testo che richiede all'utente di inserire la sua data di nascita. Quando fa clic sull'icona del calendario nel campo, si apre un selettore di date agganciato sotto il campo di immissione.
@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)) }
Punti chiave sul codice
- Il selettore della data viene visualizzato quando l'utente fa clic su
IconButton
.- Il pulsante icona funge da argomento per il parametro
trailingIcon
diOutlinedTextField
. - La variabile di stato
showDatePicker
controlla la visibilità del selettore della data agganciato.
- Il pulsante icona funge da argomento per il parametro
- Il contenitore del selettore della data è un composable
Popup
, che sovrappone i contenuti senza influire sul layout di altri elementi. selectedDate
acquisisce il valore della data selezionata dall'oggettoDatePickerState
e lo formatta utilizzando la funzioneconvertMillisToDate
.- La data selezionata viene visualizzata nel campo di testo.
- Il selettore della data agganciato è posizionato sotto il campo di testo utilizzando un
offset
modificatore. - Un
Box
viene utilizzato come contenitore principale per consentire il corretto ordinamento del campo di testo e del selettore della data.
Risultati
Dopo aver fatto clic sull'icona del calendario, l'implementazione viene visualizzata nel seguente modo:
Selettore data modale
Un selettore della data modale mostra una finestra di dialogo che si apre sopra lo schermo. Per implementarlo, crea un DatePickerDialog
e passalo a un 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) } }
Punti chiave sul codice
- La funzione componibile
DatePickerModal
mostra un selettore della data modale. - L'espressione lambda
onDateSelected
viene eseguita quando l'utente seleziona una data.- Espone la data selezionata al composable principale.
- L'espressione lambda
onDismiss
viene eseguita quando l'utente chiude la dialogo.
Risultati
Questa implementazione è visualizzata come segue:
Selettore della data modale di immissione
Un selettore della data modale con input mostra una finestra di dialogo che si apre sopra lo schermo e consente all'utente di inserire una 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) } }
Punti chiave del codice
È molto simile all'esempio di selettore della data modale. La differenza principale è la seguente:
- Il parametro
initialDisplayMode
imposta la modalità di visualizzazione iniziale suDisplayMode.Input
.
Selettore della data con intervallo
Puoi creare un selettore della data che consenta all'utente di selezionare un intervallo compreso tra una data di inizio e una di fine. A tal fine, utilizza DateRangePicker
.
L'utilizzo di DateRangePicker
è essenzialmente lo stesso di DatePicker
. Puoi usarlo per un selettore agganciato come elemento secondario di PopUp
oppure come selettore modale e passarlo a DatePickerDialog
. La differenza principale è che devi utilizzare DateRangePickerState
anziché DatePickerState
.
Il seguente snippet illustra come creare un selettore di date modale con un intervallo:
@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) ) } }
Punti chiave del codice
- Il parametro
onDateRangeSelected
è un callback che riceve un valorePair<Long?, Long?>
che rappresenta le date di inizio e di fine selezionate. In questo modo, il composable principale avrà accesso all'intervallo selezionato. rememberDateRangePickerState()
crea lo stato per il selettore dell'intervallo di date.DatePickerDialog
crea un contenitore di finestre di dialogo modali.- Nel gestore
onClick
del pulsante di conferma,onDateRangeSelected
passa l'intervallo selezionato al componibile padre. - Il composable
DateRangePicker
funge da contenuto della finestra di dialogo.
Risultati
Questa implementazione è visualizzata come segue:
Utilizza la data selezionata
Per acquisire la data selezionata, monitorala nel composable principale come Long
e
trasmetti il valore a DatePicker
in onDateSelected
. Lo snippet seguente lo dimostra, anche se puoi vedere l'implementazione completa nell'app ufficiale degli snippet.
// ... 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 } ) } // ...
Lo stesso vale per i selettori di date con intervallo, anche se devi utilizzare un Pair<Long?, Long?>
o una classe di dati per acquisire i valori di inizio e di fine.