🍈

Jetpack ComposeでTimePickerをキャンセル可能にする

2023/08/16に公開

androidx.compose.material3のTimePickerをキャンセル可能にしようという趣旨の記事です。
The purpose of this article is to make TimePicker cancelable.

timePickerStateは、時計上で時間を選択したらその要素である
timePickerState.hour等が更新されてしまうので、このままだと
『OKを押すと時間の変更を確定』
『Cancelを押すと時間の変更を元に戻す』
というような動作ができません。そこで、次の拡張関数を作ります。

@OptIn(ExperimentalMaterial3Api::class)
class CustomTimePickerState (
    var timeState: TimePickerState,
    var pendingTimeState: TimePickerState
) {
    companion object {
        /**
         * The default [Saver] implementation for [CustomTimePickerState].
         */
        fun Saver(): Saver<CustomTimePickerState, *> = Saver(
            save = {
                listOf(
                    it.timeState.hour,
                    it.timeState.minute,
                    it.timeState.is24hour
                )
            },
            restore = { value ->
                CustomTimePickerState(
                    TimePickerState(
                        initialHour = value[0] as Int,
                        initialMinute = value[1] as Int,
                        is24Hour = value[2] as Boolean
                    ),
                    TimePickerState(
                        initialHour = value[0] as Int,
                        initialMinute = value[1] as Int,
                        is24Hour = value[2] as Boolean
                    )
                )
            }
        )
    }
}

@Composable
@ExperimentalMaterial3Api
fun rememberCustomTimePickerState(
    initialHour: Int = 0,
    initialMinute: Int = 0,
    is24Hour: Boolean = DateFormat.is24HourFormat(LocalContext.current),
): CustomTimePickerState {
    return rememberSaveable(
        saver = CustomTimePickerState.Saver()
    ) {
        CustomTimePickerState(
            TimePickerState(
                initialHour = initialHour,
                initialMinute = initialMinute,
                is24Hour = is24Hour,
            ),
            TimePickerState(
                initialHour = initialHour,
                initialMinute = initialMinute,
                is24Hour = is24Hour,
            )
        )
    }
}

stateに新規にpendingTimeStateを追加しています。
これを次のように実装します。

var showTimePickerDialog by remember { mutableStateOf(false) }
val customState = rememberCustomTimePickerState()
if (showTimePickerDialog) {
    TimePickerDialog(
        },
        onConfirm = {
            showTimePickerLeftDialog = false
	    timePickerState.pendingTimeState = TimePickerState(
		timePickerState.timeState.hour,
		timePickerState.timeState.minute,
		timePickerState.timeState.is24hour
	    )
        },
        onDismiss = {
            showDatePickerDialog = false
	    timePickerState.timeState = TimePickerState(
		timePickerState.pendingTimeState.hour,
		timePickerState.pendingTimeState.minute,
		timePickerState.pendingTimeState.is24hour
	    )
        }
    ) {
        DatePicker(
            TimePicker(state = timePickerState.pendingTimeState)
        )
    }
}
株式会社THIRD エンジニアブログ

Discussion