חלוניות לבחירת תאריך מאפשרות למשתמשים לבחור תאריך, טווח תאריכים או את שניהם. הם משתמשים בתיבת דו-שיח של לוח שנה או בשדה להזנת טקסט כדי לאפשר למשתמשים לבחור תאריכים.
סוגים
יש שלושה סוגים של חלוניות לבחירת תאריך:
- מעוגן: מופיע בתוך השורה בפריסה. הוא מתאים לפריסות קומפקטיות שבהן תיבת דו-שיח ייעודית עלולה להפריע.
- מודאלי: מופיע כתיבת דו-שיח שמוצגת מעל התוכן של האפליקציה. כך המשתמשים יכולים להתמקד בבחירת התאריך.
- קלט מודאלי: שילוב של שדה טקסט עם חלונית מודאלית לבחירת תאריך.
כדי להטמיע את החלוניות האלה לבחירת תאריך באפליקציה, אפשר להשתמש ברכיבים הבאים שניתנים לשילוב:
-
DatePicker: פונקציה כללית של Composable לחלונית לבחירת תאריך. המאגר שבו אתם משתמשים קובע אם הוא מעוגן או מודל. -
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.- כפתור הסמל משמש כארגומנט לפרמטר
trailingIconשלOutlinedTextField. - משתנה המצב
showDatePickerקובע את החשיפה של החלונית לבחירת תאריך שעוגנה.
- כפתור הסמל משמש כארגומנט לפרמטר
- הקונטיינר של החלונית לבחירת תאריך הוא רכיב קומפוזבילי מסוג
Popup, שמופיע כשכבת-על מעל התוכן בלי להשפיע על הפריסה של רכיבים אחרים. - המשתנה
selectedDateמתעד את הערך של התאריך שנבחר מהאובייקטDatePickerStateומעצב אותו באמצעות הפונקציהconvertMillisToDate. - התאריך שנבחר מופיע בשדה הטקסט.
- החלונית לבחירת תאריך ממוקמת מתחת לשדה הטקסט באמצעות המשתנה
offset. -
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מציגה חלונית לבחירת תאריך. - ביטוי הלמבדה
onDateSelectedמופעל כשהמשתמש בוחר תאריך.- הוא חושף את התאריך שנבחר לרכיב ה-Composable ברמת ההורה.
- ביטוי הלמבדה
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הוא קריאה חוזרת (callback) שמקבלתPair<Long?, Long?>שמייצג את תאריכי ההתחלה והסיום שנבחרו. כך, לרכיב ה-composable הראשי יש גישה לטווח שנבחר. -
rememberDateRangePickerState()יוצר את המצב של בורר טווח התאריכים. - התג
DatePickerDialogיוצר מאגר של תיבת דו-שיח מודאלית. - ב-handler של
onClickבכפתור האישור,onDateRangeSelectedמעביר את הטווח שנבחר לרכיב הקומפוזבילי הראשי. - הקומפוזבילי
DateRangePickerמשמש כתוכן של תיבת הדו-שיח.
תוצאות
ההטמעה הזו נראית כך:
שימוש בתאריך שנבחר
כדי לתעד את התאריך שנבחר, עוקבים אחריו ברכיב ה-parent הניתן לקישור בתור Long ומעבירים את הערך אל DatePicker ב-onDateSelected. קטע הקוד הבא מדגים את זה, אבל אפשר לראות את ההטמעה המלאה באפליקציית קטעי הקוד הרשמית.
// ... var selectedDate by remember { mutableStateOf<Long?>(null) } // ... if (selectedDate != null) { val date = Date(selectedDate!!) val formattedDate = SimpleDateFormat("MMM dd, yyyy", LocalLocale.current.platformLocale).format(date) Text("Selected date: $formattedDate") } else { Text("No date selected") } // ... DatePickerModal( onDateSelected = { selectedDate = it showModal = false }, onDismiss = { showModal = false } ) } // ...
אותו עיקרון חל על חלוניות לבחירת טווח תאריכים, אבל צריך להשתמש ב-Pair<Long?, Long?> או במחלקת נתונים כדי לתעד את ערכי ההתחלה והסיום.