JetPack Compose: DatePicker-TextField

Max Großmann
4 min readJan 13, 2021

--

Intro

Jetpack Compose is the new toolkit for android to build native user interfaces. To get started, i highly recommend going through the “Jetpack Compose basics” Codelab by Google. If you prefer video content, the youtuber CodingWithMitch has a complete course on how to build apps with jetpack compose.

Please note that jetpack compose is not stable yet, so changes in the API might be possible.

Demo

In this blogpost i want to share, how to build a simple datepicker textfield, that looks like that:

When you click the text field, a datepicker wil appear:

After selecting a date, the selected date should be set as textfield content:

Implementation

Create a ReadonlyTextField Component

Here we see, that jetpack compose is still in alpha. We have to start with a workaround!

We don’t want to type in the date manually, but instead launch a selection-dialog on textfield click. Unfortunatly there is no way to prevent opening the virtual keyboard as far as i know. It’s possbile to close the keyboard immediatly after opening, but that looks kind of glitchy, when the keyboard is appearing and disappearing in the same second.

This implementation prevents the keyboard from appearing by placing a invisible box overlaying the textfield. The box has the same size as the text field. To implement custom click behaviour, we add a click-handler to the box-modifier.

This is a possbile implementation of a ReadonlyTextField:

@Composable
fun ReadonlyTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
modifier: Modifier = Modifier,
onClick: () -> Unit,
label: @Composable () -> Unit
) {
Box {
TextField(
value = value,
onValueChange = onValueChange,
modifier = modifier,
label = label
)
Box(
modifier = Modifier
.matchParentSize()
.alpha(0f)
.clickable(onClick = onClick),
)
}
}

Implementation of the dialog

There is a nice open source lib named compose-material-dialogs, that provides datepicker and a lot of other material dialogs for jetpack compose. Credits go to vanpra for this great library!

In order to use the date picker, we have to add the following dependency to apps build.gradle

implementation "com.vanpra.compose-material-dialogs:datetime:0.2.9"

The sample code in the documentation shows how to launch a dialog and react on the selected input:

val dialog = MaterialDialog()
dialog.build {
...
datepicker { date ->
// Do stuff with passed in java.time.LocalDate object
}
}
dialog.show()

Unfortunately, minSdkVersion has to be 26 (Android 8) in order to access methods of the LocalDate-Class. I opened an issue in the github project, so you can see if there is a workaround for this.

Compose ReadonlyTextField and Dialog together

Next we create a new composable named MyDateField and compose the dialog and the ReadonlyTextField together.

We show the dialog in the onClick-Parameter of the ReadonlyTextField. When we select a date in the picker, the value gets formatted and set to the textState-Property. That will trigger rerendering of the composable and display the textState-Value inside the textfield.

@Composable
fun MyDateField() {
val dialog = MaterialDialog()
val textState = remember { mutableStateOf(TextFieldValue()) }
dialog.build {
datepicker { date ->
val formattedDate = date.format(
DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
textState.value = TextFieldValue(formattedDate)
}
}
Column(modifier = Modifier.padding(16.dp)) {
ReadonlyTextField(
value = textState.value,
onValueChange = { textState.value = it },
onClick = {
dialog.show()
},
label = {
Text(text = "Date")
}
)
}
}

Load MyDateField as Activity-Content

That’s all! Now add the new MyDateField-Composable to the setContent-Method of your activity or add it to another already existing composable.

override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContent {
MyDateField()
}
}

Hope you look forward of a stable version of compose as much as i do!

Have a nice day. ~Max

--

--