Jetpack Compose – DatePicker Easy to Implement

There are some options for handling dates in Jetpack Compose. Recently, I found a very straightforward library for this porpuse.

We need two things:

  • A TextField in which we are going to show the date
  • A Calendar picker that helps us to select the date

We are going to use the Calendar Picker in this github repo:

https://github.com/maxkeppeler/sheets-compose-dialogs

First, we put the dependencies of the Calendar library in the build.gradle.kts file

dependencies {

    implementation("com.maxkeppeler.sheets-compose-dialogs:core:1.2.0")
    implementation("com.maxkeppeler.sheets-compose-dialogs:calendar:1.2.0")
    
}

Next, lets create a new Composable and put the example given by the library

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomDatePicker() {
    val selectedDate = remember { mutableStateOf(LocalDate.now())}

    CalendarDialog(
        state = rememberUseCaseState(visible = true, true, onCloseRequest = { } ),
        config = CalendarConfig(
            yearSelection = true,
            style = CalendarStyle.MONTH,
        ),
        selection = CalendarSelection.Date(
            selectedDate = selectedDate.value
        ) { newDate ->
            selectedDate.value = newDate
        },
    )
}

This is how the example looks like

Now, lets put a TextField to show the date

    TextField(
        value = selectedDate.value.format(DateTimeFormatter.ISO_DATE) ,
        onValueChange = {}
    )

Now, we need to add functionality to open the dialog. We want that the dialog opens when the TextField is clicked. So, we need a variable that handles the open state.

 val open = remember { mutableStateOf(false)}

And we add the clicked event

    TextField(
        modifier = Modifier.clickable { //Click event
            open.value = true
        },
        value = selectedDate.value.format(DateTimeFormatter.ISO_DATE) ,
        onValueChange = {}
    )

You will notice that the click event does not work you have to disable the TextField and modify the colors.

    TextField(
        modifier = Modifier.clickable { //Click event
            open.value = true
        },
        enabled = false,// <- Add this to make click event work
        value = selectedDate.value.format(DateTimeFormatter.ISO_DATE) ,
        onValueChange = {},
        colors = TextFieldDefaults.outlinedTextFieldColors(
            disabledTextColor = MaterialTheme.colorScheme.onSurface,
            disabledBorderColor = MaterialTheme.colorScheme.outline,
            disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,
            disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
            disabledLeadingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
            disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant)
    )

Finally, we display the dialog only when open state is true

    if (open.value) {
        CalendarDialog(
            state = rememberUseCaseState(visible = true, true, onCloseRequest = { } ),
            config = CalendarConfig(
                yearSelection = true,
                style = CalendarStyle.MONTH,
            ),
            selection = CalendarSelection.Date(
                selectedDate = selectedDate.value
            ) { newDate ->
                selectedDate.value = newDate
            },
        )
    }

Additionally, we are going to add the parameters to change the value from outside the composable

fun CustomDatePicker(
    value: LocalDate,
    onValueChange: (LocalDate) -> Unit
) 

We can use the Composable like this

@Preview
@Composable
fun CustomDatePickerPreview(){
    CustomdatepickerTheme {
        val date = remember { mutableStateOf(LocalDate.now())}
        CustomDatePicker(
            value = date.value,
            onValueChange = {date.value = it}
        )
    }
}

This is the whole code

import androidx.compose.foundation.clickable
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.calendar.CalendarDialog
import com.maxkeppeler.sheets.calendar.models.CalendarConfig
import com.maxkeppeler.sheets.calendar.models.CalendarSelection
import com.maxkeppeler.sheets.calendar.models.CalendarStyle
import com.thisisthetime.customdatepicker.ui.theme.CustomdatepickerTheme
import java.time.LocalDate
import java.time.format.DateTimeFormatter

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CustomDatePicker(
    value: LocalDate,
    onValueChange: (LocalDate) -> Unit
) {

    val open = remember { mutableStateOf(false)}

    if (open.value) {
        CalendarDialog(
            state = rememberUseCaseState(visible = true, true, onCloseRequest = { open.value = false } ),
            config = CalendarConfig(
                yearSelection = true,
                style = CalendarStyle.MONTH,
            ),
            selection = CalendarSelection.Date(
                selectedDate = value
            ) { newDate ->
                onValueChange(newDate)
            },
        )
    }

    TextField(
        modifier = Modifier.clickable { //Click event
            open.value = true
        },
        enabled = false,// <- Add this to make click event work
        value = value.format(DateTimeFormatter.ISO_DATE) ,
        onValueChange = {},
        colors = TextFieldDefaults.outlinedTextFieldColors(
            disabledTextColor = MaterialTheme.colorScheme.onSurface,
            disabledBorderColor = MaterialTheme.colorScheme.outline,
            disabledPlaceholderColor = MaterialTheme.colorScheme.onSurfaceVariant,
            disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
            disabledLeadingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
            disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant)
    )
}

@Preview
@Composable
fun CustomDatePickerPreview(){
    CustomdatepickerTheme {
        val date = remember { mutableStateOf(LocalDate.now())}
        CustomDatePicker(
            value = date.value,
            onValueChange = {date.value = it}
        )
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *