Tarih seçiciler

Tarih seçiciler, kullanıcıların tarih, tarih aralığı veya her ikisini de seçmesine olanak tanır. Kullanıcıların tarih seçmesine olanak tanımak 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 üzerinde yer alan bir iletişim kutusu olarak görünür. Bu, tarih seçimine net bir şekilde odaklanmanızı sağlar.
  • Modal giriş: Bir metin alanını modal tarih seçiciyle birleştirir.

Aşağıdaki composable'ları kullanarak bu tarih seçicileri uygulamanıza ekleyebilirsiniz:

  • DatePicker: Tarih seçici için genel composable. Kullandığınız kapsayıcı, yerleştirilmiş mi yoksa model mi olduğunu belirler.
  • DatePickerDialog: Hem modal hem de modal giriş tarih seçicilerin kapsayıcısı.
  • DateRangePicker: Kullanıcının başlangıç ve bitiş tarihi içeren bir aralık seçebildiği tüm tarih seçiciler için.

Eyalet

Farklı tarih seçici composable'ların ortak olarak kullandığı anahtar parametre state'dır. Bu parametre, DatePickerState veya DateRangePickerState nesnesi alır. Bu özellikler, tarih seçiciyi kullanarak kullanıcının seçimiyle ilgili bilgileri (ör. mevcut seçili 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.

Sabitlenmiş tarih seçici

Aşağıdaki örnekte, kullanıcıdan doğum tarihini girmesini isteyen bir metin alanı bulunmaktadı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 parametresinin bağımsız değişkeni olarak kullanılır.trailingIcon
    • 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 composable'dır.
  • selectedDate, DatePickerState nesnesinden seçilen tarihin değerini alır ve convertMillisToDate işlevini kullanarak biçimlendirir.
  • Seçilen tarih, metin alanında görünür.
  • Sabitlenmiş tarih seçici, offset değiştiricisi kullanılarak metin alanının altına yerleştirilir.
  • Metin alanının ve tarih seçicinin düzgün şekilde katmanlanmasına izin vermek için kök kapsayıcı olarak Box kullanılır.

Sonuçlar

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

Sabitlenmiş tarih seçici örneği.
1. şekil. Sabitlenmiş bir tarih seçici.

Modal tarih seçici, ekranın üzerinde kayan bir iletişim kutusu gösterir. Bu özelliği uygulamak için bir DatePickerDialog oluşturun ve DatePicker iletin.

@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çiciyi gösterir.
  • Kullanıcı bir tarih seçtiğinde onDateSelected lambda ifadesi yürütülür.
    • Seçilen tarihi üst composable'a aktarır.
  • 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. Modal tarih seçici.

Giriş modal tarih seçicisi

Girişli bir modal tarih seçici, ekranın üzerinde kayan 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ğine çok benzer. Temel fark şudur:

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

Aralıklı tarih seçici

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

DateRangePicker kullanımı, DatePicker kullanımıyla temelde aynıdır. PopUp öğesinin alt öğesi olarak yerleştirilmiş seçici için veya modal seçici olarak kullanıp DatePickerDialog öğesine iletebilirsiniz. Aradaki temel fark, DatePickerState yerine DateRangePickerState kullanmanızdır.

Aşağıdaki snippet'te, aralıklı 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ını alan bir geri çağırmadır. Bu, üst composable'ın seçilen aralığa erişmesini sağlar.
  • 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çilen aralığı üst composable'a iletir.
  • DateRangePicker composable'ı, iletişim kutusu içeriği olarak kullanılır.

Sonuçlar

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

Modal aralık tarih seçici örneği.
4.şekil Seçili aralığı olan bir modal tarih seçici.

Seçilen tarihi kullan

Seçilen tarihi yakalamak için üst composable'da Long olarak izleyin ve değeri onDateSelected içinde DatePicker'ye iletin. Aşağıdaki snippet bunu gösterir ancak tam uygulamayı resmi snippet'ler 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 }
        )
    }
// ...

Başlangıç ve bitiş değerlerini yakalamak için Pair<Long?, Long?> veya veri sınıfı kullanmanız gerekse de tarih aralığı seçiciler için de temelde aynı durum geçerlidir.

Ayrıca bkz.