Tarih seçiciler

Tarih seçicileri, kullanıcıların tarih, tarih aralığı veya her ikisini birden seçmesine olanak tanır. Kullanıcıların tarih seçmesine izin vermek için takvim iletişim kutusu veya metin girişi kullanırlar.

Türler

Üç tür tarih seçici vardır:

  • Yuvaya yerleştirilmiş: Düzen içinde satır içi olarak görünür. Özel bir iletişim kutusunun rahatsız edici olabileceği kompakt düzenler için uygundur.
  • Modal: Uygulama içeriğinin üzerine yerleştirilmiş bir iletişim kutusu olarak görünür. Bu sayede tarih seçimine net bir şekilde odaklanabilirsiniz.
  • Modal giriş: Bir metin alanını modal tarih seçiciyle birleştirir.

Aşağıdaki bileşenleri kullanarak bu tarih seçicileri uygulamanıza uygulayabilirsiniz:

  • DatePicker: Tarih seçici için genel bir derlenebilir öğe. Kullandığınız kapsayıcı, cihazın sabitlenmiş mi yoksa model mi olduğunu belirler.
  • DatePickerDialog: Hem modal hem de modal giriş tarihi seçicilerinin kapsayıcısı.
  • DateRangePicker: Kullanıcının başlangıç ve bitiş tarihi içeren bir aralık seçebileceği tüm tarih seçicilerde.

Eyalet

Farklı tarih seçici bileşenlerinin ortak olarak kullandığı anahtar parametre state'tir. Bu parametre, DatePickerState veya DateRangePickerState nesnesi alır. Bu mülkler, tarih seçiciyi kullanarak kullanıcının seçimiyle ilgili bilgileri (ör. seçili mevcut tarih) yakalar.

Seçilen tarihi nasıl kullanabileceğiniz hakkında daha fazla bilgi için Seçilen tarihi kullanma bölümüne bakın.

Yerleştirilmiş tarih seçici

Aşağıdaki örnekte, kullanıcıdan doğum tarihini girmesini isteyen bir metin alanı vardır. Kullanıcılar alandaki takvim simgesini tıkladığında giriş alanının altında sabitlenmiş bir tarih seçici açılır.

@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))
}

Kodla ilgili önemli noktalar

  • Kullanıcı IconButton simgesini tıkladığında tarih seçici gösterilir.
    • Simge düğmesi, OutlinedTextField'nin trailingIcon parametresi için bağımsız değişken görevi görür.
    • showDatePicker durum değişkeni, sabitlenmiş tarih seçicinin görünürlüğünü kontrol eder.
  • Tarih seçicinin kapsayıcısı, diğer öğelerin düzenini etkilemeden içeriğin üzerine yerleştirilen bir Popup bileşenidir.
  • selectedDate, DatePickerState nesnesinden seçili tarihin değerini alır ve convertMillisToDate işlevini kullanarak biçimlendirir.
  • Seçilen tarih metin alanında görünür.
  • Yerleştirilmiş tarih seçici, offset değişkeni kullanılarak metin alanının altına yerleştirilir.
  • Metin alanının ve tarih seçicinin düzgün bir şekilde katmanlandırılmasına izin vermek için kök kapsayıcı olarak bir Box kullanılır.

Sonuçlar

Takvim simgesini tıkladıktan sonra bu uygulama aşağıdaki gibi görünür:

Yerleştirilmiş tarih seçici örneği.
Şekil 1. Yerleştirilmiş bir tarih seçici.

Modal tarih seçici, ekranın üzerinde yüzen bir iletişim kutusu gösterir. Bunu uygulamak için bir DatePickerDialog oluşturun ve ona bir DatePicker gönderin.

@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 composable işlevi, modal tarih seçici gösterir.
  • onDateSelected lambda ifadesi, kullanıcı bir tarih seçtiğinde yürütülür.
    • Seçilen tarihi üst bileşene gösterir.
  • onDismiss lambda ifadesi, kullanıcı iletişim kutusunu kapattığında yürütülür.

Sonuçlar

Bu uygulama aşağıdaki gibi görünür:

Modal tarih seçici örneği.
Şekil 2. Modüler tarih seçici.

Giriş modunda tarih seçici

Giriş içeren modal tarih seçici, ekranın üzerinde yüzen ve kullanıcının tarih girmesine olanak tanıyan bir iletişim kutusu gösterir.

@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)
    }
}

Bu, modal tarih seçici örneği ile neredeyse aynıdır. Başlıca fark şudur:

  • initialDisplayMode parametresi, ilk görüntüleme modunu DisplayMode.Input olarak ayarlar.
Giriş içeren modal tarih seçici.
Şekil 3. Giriş içeren modal tarih seçici.

Aralık içeren tarih seçici

Kullanıcının bir başlangıç ve bitiş tarihi arasında bir aralık seçmesine olanak tanıyan bir tarih seçici oluşturabilirsiniz. Bunun için DateRangePicker simgesini kullanın.

DateRangePicker'ün kullanımı temel olarak DatePicker ile aynıdır. PopUp öğesinin alt öğesi olarak sabitlenmiş bir seçici için kullanabilir veya modal seçici olarak kullanabilir ve DatePickerDialog öğesine iletebilirsiniz. Aradaki temel fark, DatePickerState yerine DateRangePickerState kullanmanızdır.

Aşağıdaki snippet'te, aralık içeren bir modal tarih seçicinin nasıl oluşturulacağı gösterilmektedir:

@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)
        )
    }
}

Kodla ilgili önemli noktalar

  • onDateRangeSelected parametresi, seçilen başlangıç ve bitiş tarihlerini temsil eden bir Pair<Long?, Long?> alan bir geri çağırma işlevidir. Bu, üst bileşene seçilen aralığa erişim verir.
  • rememberDateRangePickerState(), tarih aralığı seçicinin durumunu oluşturur.
  • DatePickerDialog, modal iletişim kutusu kapsayıcısı oluşturur.
  • Onay düğmesinin onClick işleyicisinde onDateRangeSelected, seçili aralığı üst bileşime iletir.
  • DateRangePicker bileşeni, iletişim kutusu içeriği olarak kullanılır.

Sonuçlar

Bu uygulama aşağıdaki gibi görünür:

Modal aralığı tarih seçici örneği.
Şekil 4. Seçili bir aralığa sahip modal tarih seçici.

Seçilen tarihi kullanma

Seçilen tarihi yakalamak için Long olarak üst bileşende izleyin ve değeri onDateSelected içindeki DatePicker'a iletin. Aşağıdaki snippet bunu göstermektedir ancak uygulamanın tamamını resmi snippet uygulamasında görebilirsiniz.

// ...
    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 }
        )
    }
// ...

Tarih aralığı seçicileri için de temelde aynı durum geçerlidir. Ancak başlangıç ve bitiş değerlerini yakalamak için bir Pair<Long?, Long?> veya veri sınıfı kullanmanız gerekir.

Ayrıca bkz.