חלוניות לבחירת תאריך מאפשרות למשתמשים לבחור תאריך, טווח תאריכים או את שניהם. הם משתמשים בתיבת דו-שיח של היומן או בקלט טקסט כדי לאפשר למשתמשים לבחור תאריכים.
סוגים
יש שלושה סוגים של כלי לבחירת תאריך:
- בעגינה: מופיע בתוך השורה בפריסה. האפשרות הזו מתאימה לפריסות קומפקטיות שבהן הצגת תיבת דו-שיח ייעודית עלולה להפריע.
- מודאלית: מופיעה כתיבת דו-שיח שמוצגת מעל התוכן של האפליקציה. כך קל יותר להתמקד בבחירת התאריך.
- קלט במודל: שילוב של שדה טקסט עם בוחר תאריכים במודל.
אפשר להטמיע את כלי הבחירה האלה של תאריכים באפליקציה באמצעות רכיבי ה-Composable הבאים:
-
DatePicker: רכיב כללי שאפשר להשתמש בו כדי ליצור רכיב לבחירת תאריך. המכל שבו משתמשים קובע אם הוא מעוגן או מודל. -
DatePickerDialog: הקונטיינר של רכיבי בחירת התאריך במודאל ושל שדות הקלט במודאל. -
DateRangePicker: לכל כלי לבחירת תאריך שבו המשתמש יכול לבחור טווח עם תאריך התחלה ותאריך סיום.
מדינה
פרמטר המפתח שמשותף לכל רכיבי ה-Composable של כלי לבחירת תאריכים הוא state, שמקבל אובייקט DatePickerState או DateRangePickerState. המאפיינים שלהם מתעדים מידע על הבחירה של המשתמש באמצעות חלונית לבחירת תאריך, כמו התאריך הנוכחי שנבחר.
מידע נוסף על השימוש בתאריך שנבחר מופיע בקטע שימוש בתאריך שנבחר.
החלונית לבחירת תאריך מעוגנת
בדוגמה הבאה, יש שדה טקסט שמבקש מהמשתמש להזין את תאריך הלידה שלו. כשלוחצים על סמל היומן בשדה להזנת קלט, נפתח בורר תאריכים מעוגן מתחת לשדה להזנת קלט.
@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)) }
מידע חשוב על הקוד
- הכלי לבחירת תאריך מופיע כשהמשתמש לוחץ על
IconButton.- לחצן הסמל משמש כארגומנט לפרמטר
OutlinedTextField'strailingIcon. - משתנה המצב
showDatePickerקובע אם חלונית התאריכים תהיה מוצמדת.
- לחצן הסמל משמש כארגומנט לפרמטר
- הקונטיינר של בוחר התאריכים הוא רכיב קומפוזבילי
Popup, שמוצג כשכבת-על מעל התוכן בלי להשפיע על הפריסה של רכיבים אחרים. -
selectedDateמחלץ את הערך של התאריך שנבחר מהאובייקטDatePickerStateומעצב אותו באמצעות הפונקציהconvertMillisToDate. - התאריך שנבחר מופיע בשדה הטקסט.
- המיקום של לוח השנה הצמוד לשדה הטקסט מוגדר באמצעות
offsetmodifier. - השתמשנו ב-
Boxכמאגר הבסיסי כדי לאפשר שכבות מתאימות של שדה הטקסט ושל הכלי לבחירת תאריך.
תוצאות
אחרי שלוחצים על סמל היומן, ההטמעה הזו מופיעה כך:
חלונית מודאלית לבחירת תאריך
כלי לבחירת תאריך במצב מודאלי מציג תיבת דו-שיח שצפה מעל המסך. כדי להטמיע את התכונה, יוצרים DatePickerDialog ומעבירים לו 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) } }
מידע חשוב על הקוד
- הפונקציה הניתנת להגדרה
DatePickerModalמציגה חלונית מודאלית לבחירת תאריך. - ביטוי ה-lambda
onDateSelectedמופעל כשהמשתמש בוחר תאריך.- הוא חושף את התאריך שנבחר לרכיב ההורה הניתן להרכבה.
- ביטוי ה-lambda
onDismissמופעל כשהמשתמש סוגר את תיבת הדו-שיח.
תוצאות
ההטמעה הזו נראית כך:
הזנת תאריך בחלונית לבחירת תאריך
לוח שנה מודאלי לבחירת תאריך עם שדה קלט מציג תיבת דו-שיח שמופיעה מעל המסך ומאפשרת למשתמש להזין תאריך.
@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) } }
מידע חשוב על הקוד
הדוגמה הזו דומה מאוד לדוגמה של חלונית לבחירת תאריך. ההבדל העיקרי הוא:
- הפרמטר
initialDisplayModeמגדיר את מצב התצוגה הראשוני ל-DisplayMode.Input.
חלונית לבחירת תאריך עם טווח
אפשר ליצור חלונית לבחירת תאריך שמאפשרת למשתמש לבחור טווח בין תאריך התחלה לתאריך סיום. כדי לעשות את זה, משתמשים בפקודה DateRangePicker.
השימוש ב-DateRangePicker זהה בעצם לשימוש ב-DatePicker. אפשר להשתמש בו כבוחר מעוגן כצאצא של PopUp, או כבוחר מודאלי ולהעביר אותו אל DatePickerDialog. ההבדל העיקרי הוא שמשתמשים ב-DateRangePickerState במקום ב-DatePickerState.
בדוגמה הבאה אפשר לראות איך יוצרים בוחר תאריכים מודאלי עם טווח:
@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) ) } }
מידע חשוב על הקוד
- הפרמטר
onDateRangeSelectedהוא קריאה חוזרת שמקבלתPair<Long?, Long?>שמייצג את תאריכי ההתחלה והסיום שנבחרו. כך, לרכיב הניתן להרכבה ברמת ההורה יש גישה לטווח שנבחר. -
rememberDateRangePickerState()יוצר את המצב של הכלי לבחירת טווח תאריכים. - התג
DatePickerDialogיוצר מאגר של תיבת דו-שיח מודאלית. - ב-handler של לחצן האישור, הפונקציה
onClickonDateRangeSelectedמעבירה את הטווח שנבחר לרכיב הקומפוזבילי של ההורה. - הקומפוזבל
DateRangePickerמשמש כתוכן של תיבת הדו-שיח.
תוצאות
ההטמעה הזו נראית כך:
שימוש בתאריך שנבחר
כדי לתעד את התאריך שנבחר, עוקבים אחריו בקומפוזיציה הראשית כ-Long ומעבירים את הערך אל DatePicker ב-onDateSelected. קטע הקוד הבא מדגים את זה, אבל אפשר לראות את ההטמעה המלאה באפליקציית קטעי הקוד הרשמית.
// ... 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 } ) } // ...
אותו הדבר נכון גם לגבי כלי לבחירת תאריכים בטווח, אבל צריך להשתמש ב-Pair<Long?, Long?> או במחלקת נתונים כדי לתעד את ערכי ההתחלה והסיום.