androidkotlinandroid-jetpack-composedialogandroid-datepicker

Date Picker Dialog not opening


I'm creating a date-of-birth picker screen with Jetpack Compose in Kotlin, where I need to let users select a date using a DatePickerDialog. I'm invoking this Composable function within onCreate() using setContent {. }. The UI displays a rectangular OutlinedTextField with the placeholder "Tap to select DOB", but when I click on it, nothing appears — the date picker dialog isn't shown.

Therefore, no date is picked, and the "Next" button is greyed out (disabled) because it's dependent on a non-empty DOB field.

I've checked that the clickable modifier is being applied, and I've also put the dialog within remember {. }. Nevertheless, the dialog never opens when clicking the field.

My objective is to enable users to select a valid birth date from a calendar dialog, and when selected, allow the "Next" button to advance.

Can anyone provide some insight into why the DatePickerDialog isn't displaying, and how one should actually trigger it in a Jetpack Compose environment?

@Composable
fun ChooseDob(
    onDobSelected: (String) -> Unit
) {
    val context = LocalContext.current
    var dob by remember { mutableStateOf("") }

    val calendar = Calendar.getInstance()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(32.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Select your Date of Birth",
            style = MaterialTheme.typography.headlineMedium,
            color = Color.Black,
            fontSize = 24.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.align(Alignment.Start)
        )

        Spacer(modifier = Modifier.height(16.dp))

        OutlinedTextField(
            value = dob,
            onValueChange = {},
            modifier = Modifier
                .fillMaxWidth()
                .clickable {
                    val datePickerDialog = DatePickerDialog(
                        context,
                        { _, year, month, dayOfMonth ->
                            val selectedCalendar = Calendar.getInstance().apply {
                                set(Calendar.YEAR, year)
                                set(Calendar.MONTH, month)
                                set(Calendar.DAY_OF_MONTH, dayOfMonth)
                            }

                            val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.US)
                            dob = formatter. Format(selectedCalendar.time)
                        },
                        calendar.get(Calendar.YEAR),
                        calendar.get(Calendar.MONTH),
                        calendar.get(Calendar.DAY_OF_MONTH)
                    ).apply {
                        datePicker.maxDate = System.currentTimeMillis()
                    }

                    datePickerDialog.show()
                },
            readOnly = true,
            placeholder = { Text("Tap to select DOB") }
        )

        Spacer(modifier = Modifier.height(16.dp))

        Button(
            onClick = { onDobSelected(dob) },
            enabled = dob.isNotBlank(),
            modifier = Modifier.align(Alignment.End),
            colors = ButtonDefaults.buttonColors(
                containerColor = if (dob.isNotBlank()) Color(0xFF2196F3) else Color.Gray
            )
        ) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Icon(
                    imageVector = Icons.AutoMirrored.Filled.ArrowForward,
                    contentDescription = "Next",
                    tint = Color.White
                )
            }
        }
    }
}

Solution

  • The OutlinedTextField has its own internal focus handling, and using clickable on it can sometimes interfere with its behavior. Instead, you should wrap the OutlinedTextField in a Box or another container and apply the clickable modifier to that container.

    @Composable
    fun ChooseDob(
        onDobSelected: (String) -> Unit
    ) {
        val context = LocalContext.current
        var dob by remember { mutableStateOf("") }
    
        val calendar = Calendar.getInstance()
    
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(32.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "Select your Date of Birth",
                style = MaterialTheme.typography.headlineMedium,
                color = Color.Black,
                fontSize = 24.sp,
                fontWeight = FontWeight.Bold,
                modifier = Modifier.align(Alignment.Start)
            )
    
            Spacer(modifier = Modifier.height(16.dp))
    
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable {
                        val datePickerDialog = DatePickerDialog(
                            context,
                            { _, year, month, dayOfMonth ->
                                val selectedCalendar = Calendar.getInstance().apply {
                                    set(Calendar.YEAR, year)
                                    set(Calendar.MONTH, month)
                                    set(Calendar.DAY_OF_MONTH, dayOfMonth)
                                }
    
                                val formatter = SimpleDateFormat("yyyy-MM-dd", Locale.US)
                                dob = formatter.format(selectedCalendar.time)
                            },
                            calendar.get(Calendar.YEAR),
                            calendar.get(Calendar.MONTH),
                            calendar.get(Calendar.DAY_OF_MONTH)
                        ).apply {
                            datePicker.maxDate = System.currentTimeMillis()
                        }
    
                        datePickerDialog.show()
                    }
            ) {
                OutlinedTextField(
                    value = dob,
                    onValueChange = {},
                    modifier = Modifier.fillMaxWidth(),
                    readOnly = true,
                    placeholder = { Text("Tap to select DOB") }
                )
            }
    
            Spacer(modifier = Modifier.height(16.dp))
    
            Button(
                onClick = { onDobSelected(dob) },
                enabled = dob.isNotBlank(),
                modifier = Modifier.align(Alignment.End),
                colors = ButtonDefaults.buttonColors(
                    containerColor = if (dob.isNotBlank()) Color(0xFF2196F3) else Color.Gray
                )
            ) {
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Icon(
                        imageVector = Icons.AutoMirrored.Filled.ArrowForward,
                        contentDescription = "Next",
                        tint = Color.White
                    )
                }
            }
        }
    }