I have this code from the material3 documentation for compose:
import androidx.compose.foundation.layout.Box
import androidx.compose.material3.Button
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TimeInput
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
var showTimePicker by remember { mutableStateOf(false) }
val state = rememberTimePickerState()
val formatter = remember { SimpleDateFormat("hh:mm a", Locale.getDefault()) }
val snackState = remember { SnackbarHostState() }
val snackScope = rememberCoroutineScope()
Box(propagateMinConstraints = false) {
Button(
modifier = Modifier.align(Alignment.Center),
onClick = { showTimePicker = true }
) { Text("Set Time") }
SnackbarHost(hostState = snackState)
}
if (showTimePicker) {
TimePickerDialog(
onCancel = { showTimePicker = false },
onConfirm = {
val cal = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, state.hour)
cal.set(Calendar.MINUTE, state.minute)
cal.isLenient = false
snackScope.launch {
snackState.showSnackbar("Entered time: ${formatter.format(cal.time)}")
}
showTimePicker = false
},
) {
TimeInput(state = state)
}
}
Pretty straightforward right?
But android studio is complaining about TimePickerDialog with:
<html>None of the following functions can be called with the arguments supplied:<br/>public constructor TimePickerDialog(context: Context!, listener: TimePickerDialog.OnTimeSetListener!, hourOfDay: Int, minute: Int, is24HourView: Boolean) defined in android.app.TimePickerDialog<br/>public constructor TimePickerDialog(context: Context!, themeResId: Int, listener: TimePickerDialog.OnTimeSetListener!, hourOfDay: Int, minute: Int, is24HourView: Boolean) defined in android.app.TimePickerDialog
With a bit of googling of found most of the example code regarding TimePickerDialog or DatePickerDialog weren't using the Picker dialogs as explained in the documentation above.
val mTimePickerDialog = TimePickerDialog(
mContext,
{_, mHour : Int, mMinute: Int ->
mTime.value = "$mHour:$mMinute"
}, mHour, mMinute, false
)
The TimePickerDialog is not included in the M3 package (1.1.0-beta01).
You can use:
@Composable
fun TimePickerDialog(
title: String = "Select Time",
onCancel: () -> Unit,
onConfirm: () -> Unit,
toggle: @Composable () -> Unit = {},
content: @Composable () -> Unit,
) {
Dialog(
onDismissRequest = onCancel,
properties = DialogProperties(
usePlatformDefaultWidth = false
),
) {
Surface(
shape = MaterialTheme.shapes.extraLarge,
tonalElevation = 6.dp,
modifier = Modifier
.width(IntrinsicSize.Min)
.height(IntrinsicSize.Min)
.background(
shape = MaterialTheme.shapes.extraLarge,
color = MaterialTheme.colorScheme.surface
),
) {
Column(
modifier = Modifier.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 20.dp),
text = title,
style = MaterialTheme.typography.labelMedium
)
content()
Row(
modifier = Modifier
.height(40.dp)
.fillMaxWidth()
) {
toggle()
Spacer(modifier = Modifier.weight(1f))
TextButton(
onClick = onCancel
) { Text("Cancel") }
TextButton(
onClick = onConfirm
) { Text("OK") }
}
}
}
}
}

Source code
Gabriele answer is fine for the classic TimePicker, if you need both modes Input and Picker, this is the full code adapted from his source code link.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimePickerDialog(
onCancel: () -> Unit,
onConfirm: (Calendar) -> Unit,
modifier: Modifier = Modifier
) {
val time = Calendar.getInstance()
time.timeInMillis = System.currentTimeMillis()
var mode: DisplayMode by remember { mutableStateOf(DisplayMode.Picker) }
val timeState: TimePickerState = rememberTimePickerState(
initialHour = time[Calendar.HOUR_OF_DAY],
initialMinute = time[Calendar.MINUTE],
)
fun onConfirmClicked() {
val cal = Calendar.getInstance()
cal.set(Calendar.HOUR_OF_DAY, timeState.hour)
cal.set(Calendar.MINUTE, timeState.minute)
cal.isLenient = false
onConfirm(cal)
}
// TimePicker does not provide a default TimePickerDialog, so we use our own PickerDialog:
// https://issuetracker.google.com/issues/288311426
PickerDialog(
modifier = modifier,
onDismissRequest = onCancel,
title = { Text("Select hour") },
buttons = {
DisplayModeToggleButton(
displayMode = mode,
onDisplayModeChange = { mode = it },
)
Spacer(Modifier.weight(1f))
TextButton(onClick = onCancel) {
Text("Cancel")
}
TextButton(onClick = ::onConfirmClicked) {
Text("Confirm")
}
},
) {
val contentModifier = Modifier.padding(horizontal = 24.dp)
when (mode) {
DisplayMode.Picker -> TimePicker(modifier = contentModifier, state = timeState)
DisplayMode.Input -> TimeInput(modifier = contentModifier, state = timeState)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun DisplayModeToggleButton(
displayMode: DisplayMode,
onDisplayModeChange: (DisplayMode) -> Unit,
modifier: Modifier = Modifier,
) {
when (displayMode) {
DisplayMode.Picker -> IconButton(
modifier = modifier,
onClick = { onDisplayModeChange(DisplayMode.Input) },
) {
Icon(
painter = painterResource(id = R.drawable.ic_keyboard),
contentDescription = "",
)
}
DisplayMode.Input -> IconButton(
modifier = modifier,
onClick = { onDisplayModeChange(DisplayMode.Picker) },
) {
Icon(
painter = painterResource(id = R.drawable.ic_schedule),
contentDescription = "",
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PickerDialog(
onDismissRequest: () -> Unit,
title: @Composable () -> Unit,
buttons: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit,
) {
AlertDialog(
modifier = modifier
.width(IntrinsicSize.Min)
.height(IntrinsicSize.Min),
onDismissRequest = onDismissRequest,
properties = DialogProperties(usePlatformDefaultWidth = false),
) {
Surface(
shape = MaterialTheme.shapes.extraLarge,
tonalElevation = 6.dp,
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
// Title
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) {
ProvideTextStyle(MaterialTheme.typography.labelLarge) {
Box(
modifier = Modifier
.align(Alignment.Start)
.padding(horizontal = 24.dp)
.padding(top = 16.dp, bottom = 20.dp),
) {
title()
}
}
}
// Content
CompositionLocalProvider(LocalContentColor provides AlertDialogDefaults.textContentColor) {
content()
}
// Buttons
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.primary) {
ProvideTextStyle(MaterialTheme.typography.labelLarge) {
// TODO This should wrap on small screens, but we can't use AlertDialogFlowRow as it is no public
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 8.dp, end = 6.dp, start = 6.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End),
) {
buttons()
}
}
}
}
}
}
}
[
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With