時間挑選器的對話方塊

時間挑選器通常會顯示在對話方塊中。您可以使用相對一般且最少的對話方塊實作方式,也可以實作彈性更高的自訂對話方塊。

如要進一步瞭解對話方塊 (包括如何使用時間選擇器狀態),請參閱時間選擇器指南

基本範例

如要為時間挑選器建立對話方塊,最簡單的方法是建立實作 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. 自訂對話方塊中的時間挑選器。

其他資源