7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[material3] Jetpack ComposeでDate Pickerを表示する

Last updated at Posted at 2023-01-29

背景

Compose Material3の1.1.0-alpha04Date Picker が追加されました。
これの使い方について、現時点で日本語の記事が見つからなかったので、簡単にまとめます。
なおアルファ版での確認のため、今後変更される可能性が大いにあります。

実行環境

app/build.gradle
implementation 'androidx.compose.material3:material3:1.1.0-alpha04'

まず表示してみる

MyDatePicker.kt
@ExperimentalMaterial3Api
@Composable
fun MyDatePicker() {
    DatePicker(datePickerState = rememberDatePickerState())
}

@ExperimentalMaterial3Api
@Preview(showBackground = true, device = Devices.PIXEL)
@Composable
fun MyDatePickerPreview() {
    MyDatePicker()
}

DatePickerは現在実験的なComposeのため、@ExperimentalMaterial3Apiアノテーションを付けています。
上記のコードにより下記プレビューが表示されます。
デフォルトで今月が表示され、本日の日付が丸で囲われるようです。
スクリーンショット 2023-01-25 22.45.05.png

ここでプレビューをInteractive Modeで実行し、1月27日をタップするとどうなるでしょうか。
スクリーンショット 2023-01-25 22.44.35.png
タップした日付が、紫で塗り潰された丸で囲われました。
表示される日付の表記が少しおかしいですね。

DatePickerの実装

ここで、DatePickerの実装を見てみます。

DatePicker.kt
@ExperimentalMaterial3Api
@Composable
fun DatePicker(
    datePickerState: DatePickerState,
    modifier: Modifier = Modifier,
    dateFormatter: DatePickerFormatter = remember { DatePickerFormatter() },
    dateValidator: (Long) -> Boolean = { true },
    title: (@Composable () -> Unit)? = { DatePickerDefaults.DatePickerTitle() },
    headline: @Composable () -> Unit = {
        DatePickerDefaults.DatePickerHeadline(
            datePickerState,
            dateFormatter
        )
    },
    colors: DatePickerColors = DatePickerDefaults.colors()
)

呼び出し側で必須なのはDatePickerStateだけです。
rememberDatePickerState()はDatePickerStateをrememberSaveableで覚えてくれるので、Recomposeや画面回転されても入力中の日付が消えません。また、内部で指定されているYearsRangeはIntRange(1900, 2100)だったので、デフォルトでは1900年から2100年が選択可能であるようです。

選択された日付の取得

選択された日付はDatePickerStateにエポックミリ秒で保持されています。
エポックミリ秒だと扱いづらいので、LocalDateに変換すると下記のようになります。

MyDatePicker.kt
@ExperimentalMaterial3Api
@Composable
fun MyDatePicker() {
    val datePickerState = rememberDatePickerState()
    DatePicker(datePickerState = datePickerState)
    val selectedDate: LocalDate? = datePickerState.selectedDateMillis?.let { Instant.ofEpochMilli(it).atZone(ZoneId.systemDefault()).toLocalDate() }
}

日付が選択されていない時は、エポックミリ秒がnullなので気をつけましょう。

DatePickerのカスタマイズ

先ほど表示したDatePickerに下記の要件を加えます。

  • 2023年2月を初期表示する
  • 2023年2月15日をデフォルトで選択する
  • 日付を日本語のフォーマットで表示する
MyDatePicker.kt
@ExperimentalMaterial3Api
@Composable
private fun MyDatePicker() {
    val initialSelectedDateMillis = LocalDate.of(2023, 2, 15)
        .atStartOfDay()
        .toEpochSecond(ZoneOffset.UTC)
        .toMillis()
    DatePicker(
        datePickerState = rememberDatePickerState(
            initialSelectedDateMillis,
            initialSelectedDateMillis
        ),
        dateFormatter = DatePickerFormatter(
            shortFormat = "M月 d日 (E)", // 今年の日付を選択している時のフォーマット
            mediumFormat = "yyyy年 M月 d日", // 今年以外の年の日付を選択している時のフォーマット
            monthYearFormat = "yyyy年 M月" // 年月選択部分のフォーマット
        )
    )
}

private fun Long.toMillis() = this * 1000

@ExperimentalMaterial3Api
@Preview(showBackground = true, device = Devices.PIXEL)
@Composable
fun MyDatePickerPreview() {
    MyDatePicker()
}

image.png
初期表示する日付はLong(エポックミリ秒)で指定します。月も同じなので、初期表示する日付と月が同じであれば、同じ値を指定すればいいようです。
選択された日付のフォーマットも「今年を選択しているかどうか」で2つ指定する必要があります。
また今回は指定していませんが、DatePickerの色も引数で指定することができます。かつての実装(Android View)ではThemeで色指定しなければならず、さらに何の属性でどこの部分の色が変わるか分かりづらかったことを考えると、非常にやりやすくなりました。

終わりに

今回はCompose Material3のDatePickerを試してみました。
アルファ版のため仕様/実装は変わる可能性がありますが、かつての実装と比べると日付フォーマットや色など変更しやすく、直感的に使用できるいいものだと感じました。
今後安定版になることを楽しみにしています。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?