خرماچیان

انتخاب‌کنندگان تاریخ به کاربران اجازه می‌دهند تاریخ، محدوده تاریخ یا هر دو را انتخاب کنند. آنها از یک گفتگوی تقویم یا ورودی متن استفاده می کنند تا به کاربران اجازه دهند تاریخ ها را انتخاب کنند.

انواع

سه نوع خرماچین وجود دارد:

  • Docked : به صورت خطی در طرح ظاهر می شود. برای طرح‌بندی‌های فشرده که در آن یک گفتگوی اختصاصی ممکن است مزاحم به نظر برسد، مناسب است.
  • Modal : به عنوان یک گفتگو با محتوای برنامه ظاهر می شود. این امر تمرکز واضحی بر انتخاب تاریخ ایجاد می کند.
  • ورودی مودال : یک فیلد متنی را با انتخابگر تاریخ معین ترکیب می کند.

می‌توانید این انتخاب‌کننده‌های تاریخ را با استفاده از ترکیب‌پذیرهای زیر در برنامه خود پیاده‌سازی کنید:

  • DatePicker : عمومی قابل تنظیم برای انتخابگر تاریخ. ظرفی که استفاده می‌کنید تعیین می‌کند که متصل باشد یا مدل.
  • DatePickerDialog : محفظه ای برای انتخابگرهای تاریخ ورودی معین و معین.
  • DateRangePicker : برای هر انتخابگر تاریخ که در آن کاربر می تواند محدوده ای را با تاریخ شروع و پایان انتخاب کند.

ایالت

پارامتر کلیدی که ترکیب‌کننده‌های مختلف انتخابگر تاریخ به اشتراک می‌گذارند 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 Composable است که محتوا را بدون تأثیر بر چیدمان عناصر دیگر پوشش می دهد.
  • selectedDate مقدار تاریخ انتخاب شده را از شی DatePickerState می گیرد و آن را با استفاده از تابع convertMillisToDate قالب بندی می کند.
  • تاریخ انتخاب شده در قسمت متن ظاهر می شود.
  • انتخابگر تاریخ متصل در زیر فیلد نوشتاری با استفاده از یک اصلاح کننده offset قرار می گیرد.
  • یک Box به عنوان محفظه ریشه استفاده می شود تا لایه بندی مناسب فیلد متن و انتخابگر تاریخ را امکان پذیر کند.

نتایج

پس از کلیک بر روی نماد تقویم، این پیاده سازی به صورت زیر ظاهر می شود:

نمونه انتخابگر تاریخ متصل.
شکل 1. یک انتخابگر تاریخ متصل شده.

یک انتخابگر تاریخ معین یک گفتگو را نمایش می دهد که روی صفحه شناور است. برای پیاده سازی آن، یک 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 زمانی اجرا می شود که کاربر تاریخ را انتخاب کند.
    • تاریخ انتخاب شده را در معرض والد قابل ترکیب قرار می دهد.
  • عبارت onDismiss lambda زمانی اجرا می شود که کاربر گفتگو را رد کند.

نتایج

این پیاده سازی به صورت زیر ظاهر می شود:

نمونه انتخابگر تاریخ معین.
شکل 2. انتخابگر تاریخ معین.

انتخابگر تاریخ معین را وارد کنید

یک انتخابگر تاریخ معین با ورودی، گفتگویی را نمایش می دهد که روی صفحه شناور است و به کاربر اجازه می دهد تاریخ را وارد کند.

@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 تنظیم می کند.
انتخابگر تاریخ معین با ورودی.
شکل 3. انتخابگر تاریخ معین با ورودی.

انتخابگر تاریخ با محدوده

می توانید یک انتخابگر تاریخ ایجاد کنید که به کاربر امکان می دهد محدوده ای بین تاریخ شروع و پایان انتخاب کند. برای انجام این کار، از 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 یک محفظه محاوره ای معین ایجاد می کند.
  • در کنترل کننده onClick دکمه تایید، onDateRangeSelected محدوده انتخاب شده را به والد قابل تنظیم منتقل می کند.
  • قابل ترکیب DateRangePicker به عنوان محتوای گفتگو عمل می کند.

نتایج

این پیاده سازی به صورت زیر ظاهر می شود:

نمونه انتخابگر تاریخ محدوده معین.
شکل 4. انتخابگر تاریخ معین با محدوده انتخاب شده.

از تاریخ انتخاب شده استفاده کنید

برای ثبت تاریخ انتخاب شده، آن را در والد قابل تنظیم به عنوان 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?> یا یک کلاس داده برای گرفتن مقادیر شروع و پایان استفاده کنید.

همچنین ببینید