时间选择器对话框

时间选择器通常出现在对话框中。您可以使用相对通用且最小化的对话框实现,也可以实现更灵活的自定义对话框。

如需详细了解常规对话框(包括如何使用时间选择器状态),请参阅时间选择器指南

基本示例

如需为时间选择器创建对话框,最直接的方法就是创建一个实现 AlertDialog 的可组合项。以下代码段提供了使用此方法的相对最小对话框示例:

@Composable
fun DialWithDialogExample(
    onConfirm: (TimePickerState) -> Unit,
    onDismiss: () -> Unit,
) {
    val currentTime = Calendar.getInstance()

    val timePickerState = rememberTimePickerState(
        initialHour = currentTime.get(Calendar.HOUR_OF_DAY),
        initialMinute = currentTime.get(Calendar.MINUTE),
        is24Hour = true,
    )

    TimePickerDialog(
        onDismiss = { onDismiss() },
        onConfirm = { onConfirm(timePickerState) }
    ) {
        TimePicker(
            state = timePickerState,
        )
    }
}

@Composable
fun TimePickerDialog(
    onDismiss: () -> Unit,
    onConfirm: () -> Unit,
    content: @Composable () -> Unit
) {
    AlertDialog(
        onDismissRequest = onDismiss,
        dismissButton = {
            TextButton(onClick = { onDismiss() }) {
                Text("Dismiss")
            }
        },
        confirmButton = {
            TextButton(onClick = { onConfirm() }) {
                Text("OK")
            }
        },
        text = { content() }
    )
}

请注意此代码段中的要点:

  1. DialWithDialogExample 可组合项会将 TimePicker 封装在对话框中。
  2. TimePickerDialog 是一个自定义可组合项,用于使用以下参数创建 AlertDialog
    • onDismiss:在用户关闭对话框(通过关闭按钮或返回导航)时调用的函数。
    • onConfirm:在用户点击“OK”按钮时调用的函数。
    • content:用于在对话框中显示时间选择器的可组合项。
  3. AlertDialog 包括:
    • 标有“关闭”的关闭按钮。
    • 标有“确定”的确认按钮。
    • 作为 text 参数传递的时间选择器内容。
  4. DialWithDialogExample 会使用当前时间初始化 TimePickerState,并将其传递给 TimePickeronConfirm 函数。
AlertDialog 中的时间选择器,实现了标题、模式切换开关以及关闭和确认按钮。
图 1. AlertDialog 中的时间选择器。

高级示例

以下代码段演示了在 Jetpack Compose 中实现可自定义的时间选择器对话框的高级方法。

@Composable
fun AdvancedTimePickerExample(
    onConfirm: (TimePickerState) -> Unit,
    onDismiss: () -> Unit,
) {

    val currentTime = Calendar.getInstance()

    val timePickerState = rememberTimePickerState(
        initialHour = currentTime.get(Calendar.HOUR_OF_DAY),
        initialMinute = currentTime.get(Calendar.MINUTE),
        is24Hour = true,
    )

    /** Determines whether the time picker is dial or input */
    var showDial by remember { mutableStateOf(true) }

    /** The icon used for the icon button that switches from dial to input */
    val toggleIcon = if (showDial) {
        Icons.Filled.EditCalendar
    } else {
        Icons.Filled.AccessTime
    }

    AdvancedTimePickerDialog(
        onDismiss = { onDismiss() },
        onConfirm = { onConfirm(timePickerState) },
        toggle = {
            IconButton(onClick = { showDial = !showDial }) {
                Icon(
                    imageVector = toggleIcon,
                    contentDescription = "Time picker type toggle",
                )
            }
        },
    ) {
        if (showDial) {
            TimePicker(
                state = timePickerState,
            )
        } else {
            TimeInput(
                state = timePickerState,
            )
        }
    }
}

@Composable
fun AdvancedTimePickerDialog(
    title: String = "Select Time",
    onDismiss: () -> Unit,
    onConfirm: () -> Unit,
    toggle: @Composable () -> Unit = {},
    content: @Composable () -> Unit,
) {
    Dialog(
        onDismissRequest = onDismiss,
        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 = onDismiss) { Text("Cancel") }
                    TextButton(onClick = onConfirm) { Text("OK") }
                }
            }
        }
    }
}

请注意以下代码段中的要点:

  1. AdvancedTimePickerExample 可组合项会创建一个可自定义的时间选择器对话框。
  2. 它使用 Dialog 可组合项,比 AlertDialog 具有更高的灵活性。
  3. 该对话框包含一个可自定义的标题和一个用于在拨号模式和输入模式之间切换的切换按钮。
  4. Surface 会将形状和高度应用于对话框,并使用 IntrinsicSize.Min 指定宽度和高度。
  5. ColumnRow 布局提供了对话框的结构组件。
  6. 该示例使用 showDial 跟踪选择器模式。
    • IconButton 用于在模式之间切换,并相应地更新图标。
    • 对话框内容会根据 showDial 状态在 TimePickerTimeInput 之间切换。

此高级实现提供了一个高度可定制且可重复使用的时间选择器对话框,可适应应用中的不同用例。

此实现如下所示:

自定义对话框中的时间选择器,其中实现了标题、模式切换开关以及关闭和确认按钮。
图 2. 自定义对话框中的时间选择器。

其他资源