Jetpack compose. Date time picker

13,734

Solution 1

It seems they are still working on it, in the meantime if you need something very simple you can use the inter-ops of compose with Android Views:

@Composable
fun DatePicker(onDateSelected: (LocalDate) -> Unit, onDismissRequest: () -> Unit) {
    val selDate = remember { mutableStateOf(LocalDate.now()) }

    //todo - add strings to resource after POC
    Dialog(onDismissRequest = { onDismissRequest() }, properties = DialogProperties()) {
        Column(
            modifier = Modifier
                .wrapContentSize()
                .background(
                    color = MaterialTheme.colors.surface,
                    shape = RoundedCornerShape(size = 16.dp)
                )
        ) {
            Column(
                Modifier
                    .defaultMinSize(minHeight = 72.dp)
                    .fillMaxWidth()
                    .background(
                        color = MaterialTheme.colors.primary,
                        shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
                    )
                    .padding(16.dp)
            ) {
                Text(
                    text = "Select date".toUpperCase(Locale.ENGLISH),
                    style = MaterialTheme.typography.caption,
                    color = MaterialTheme.colors.onPrimary
                )

                Spacer(modifier = Modifier.size(24.dp))

                Text(
                    text = selDate.value.format(DateTimeFormatter.ofPattern("MMM d, YYYY")),
                    style = MaterialTheme.typography.h4,
                    color = MaterialTheme.colors.onPrimary
                )

                Spacer(modifier = Modifier.size(16.dp))
            }

            CustomCalendarView(onDateSelected = {
                selDate.value = it
            })

            Spacer(modifier = Modifier.size(8.dp))

            Row(
                modifier = Modifier
                    .align(Alignment.End)
                    .padding(bottom = 16.dp, end = 16.dp)
            ) {
                TextButton(
                    onClick = onDismissRequest
                ) {
                    //TODO - hardcode string
                    Text(
                        text = "Cancel",
                        style = MaterialTheme.typography.button,
                        color = MaterialTheme.colors.onPrimary
                    )
                }

                TextButton(
                    onClick = {
                        onDateSelected(selDate.value)
                        onDismissRequest()
                    }
                ) {
                    //TODO - hardcode string
                    Text(
                        text = "OK",
                        style = MaterialTheme.typography.button,
                        color = MaterialTheme.colors.onPrimary
                    )
                }

            }
        }
    }
}

@Composable
fun CustomCalendarView(onDateSelected: (LocalDate) -> Unit) {
    // Adds view to Compose
    AndroidView(
        modifier = Modifier.wrapContentSize(),
        factory = { context ->
            CalendarView(ContextThemeWrapper(context, R.style.CalenderViewCustom))
        },
        update = { view ->
            view.minDate = // contraints
            view.maxDate = // contraints

            view.setOnDateChangeListener { _, year, month, dayOfMonth ->
                onDateSelected(
                    LocalDate
                        .now()
                        .withMonth(month + 1)
                        .withYear(year)
                        .withDayOfMonth(dayOfMonth)
                )
            }
        }
    )
}

<style name="CalenderViewCustom" parent="ThemeOverlay.MaterialComponents.MaterialCalendar">
        <item name="colorAccent"><day selection color></item>
        <item name="colorOnPrimary"><text color></item>
        <item name="colorSurface"><background color></item>
</style>

You will end up with a result like this:

enter image description here

Solution 2

Using a library

As of writing, It's not implemented yet. But there is an open-source library Compose Material Dialogs

Date and Time Picker

Without a library

You can Also do this without a library, you can put it inside onclick action

private fun showDatePicker() {
    val picker = MaterialDatePicker.Builder.datePicker().build()
    activity?.let {
        picker.show(it.supportFragmentManager, picker.toString())
        picker.addOnPositiveButtonClickListener {

        }
    }
}

The old way :D

Solution 3

You can show date picker with few line in jetpack compose

 AndroidView(
            { CalendarView(it) },
            modifier = Modifier.wrapContentWidth(),
            update = { views ->
                views.setOnDateChangeListener { calendarView, i, i2, i3 ->
                }
            }
        )

Solution 4

Currently, jetpack compose is in Alpha state and there is no DateTime Picker in androidx.ui.*. But, Later android team will add it or make jetpack compose to interoperate with other components like android.widget.DatePicker Or we can develop beautiful Date Time Picker from stratch using jetpack compose like something flutter does

For now,

class DateTimeActivity : AppCompatActivity() {

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

        val c = Calendar.getInstance()
        val year = c.get(Calendar.YEAR)
        val month = c.get(Calendar.MONTH)
        val day = c.get(Calendar.DAY_OF_MONTH)
        val mHour = c[Calendar.HOUR_OF_DAY]
        val mMinute = c[Calendar.MINUTE]

        val datePickerDialog = DatePickerDialog(
            this, DatePickerDialog.OnDateSetListener
            { datePicker: DatePicker, day: Int, month: Int, year: Int ->
                setContent {
                    Column {
                        Text("$day, $month, $year")
                    }
                }
            }, year, month, day
        )


        val timePickerDialog = TimePickerDialog(
            this,
            TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute ->
                setContent {
                    Column {
                        Text("$hourOfDay:$minute")
                    }
                }
            }, mHour, mMinute, false
        )


        setContent {
            Column {
                Button(text = "Date",
                    style = OutlinedButtonStyle(),
                    onClick = {
                        datePickerDialog.show()
                    })
                Button(text = "Time",
                    style = OutlinedButtonStyle(),
                    onClick = {
                        timePickerDialog.show()
                    })
            }
        }
    }
}

Solution 5

Without 3rd party library, Using Android View solution:

import android.app.TimePickerDialog

@Composable
fun ShowTimePicker(context: Context, initHour: Int, initMinute: Int) {
    val time = remember { mutableStateOf("") }
    val timePickerDialog = TimePickerDialog(
        context,
        {_, hour : Int, minute: Int ->
            time.value = "$hour:$minute"
        }, initHour, initMinute, false
    )
    Button(onClick = {
        timePickerDialog.show()
    }) {
        Text(text = "Open Time Picker")
    }
}

UI Effect

Thanks to Kiran-Bahalaskar

Share:
13,734
Dmitrii Kargashin
Author by

Dmitrii Kargashin

Updated on June 12, 2022

Comments

  • Dmitrii Kargashin
    Dmitrii Kargashin about 2 years

    Does the jetpack compose have the date time picker view or I should create it by myself? I have tried to google it but I couldn't find ready to use component.

  • mama
    mama over 2 years
    That is nice. could you get the time as well?
  • ritwikshanker
    ritwikshanker over 2 years
    This solution requires a minimum API level of 26.
  • ShadeToD
    ShadeToD over 2 years
    @ritwikshanker If u need to use this solution in lower API just change LocalDate to Date
  • Arnyminer Z
    Arnyminer Z over 2 years
    I've adapted a little bit the code as suggested by @ShadeToD, and now it's compatible with Material Design 3. Take a look at my gist: gist.github.com/ArnyminerZ/31b82f559e3bfe42ef336f72854c5854
  • Oleksii Malovanyi
    Oleksii Malovanyi over 2 years
    It looks cool, but there is one serious issue: on activity rotation the picker would remain on the screen, but the listener would be un-attached. Also, there is no way to dismiss date-picker on orientation change as onDispose is called much later when the picker is not attached to the fragment manager..
  • Rushabh Shah
    Rushabh Shah about 2 years
    How can I add range selection to it? @Rohit Jakhar
  • Gilbert
    Gilbert about 2 years
    You can get context using: val context = LocalContext.current