DatePickerで生年月日を入力できるようにする


前提条件

SDKバージョン: 30
Androidバージョン: 9.0

この記事を書こうと思ったきっかけ

Android DatePickerで調べるとほぼ出てくるのがカレンダー形式のもので私は結構困りました。日付を選択する際は別にカレンダー形式でも問題ないと思うのですが、生年月日の選択の場合はスピナー、あるいはドラムロールと言われるタイプの形式の方が遥かに選択が楽です。
参考:【ダメなUIについて】androidの生年月日の入力フォームで使ってはいけないUIデザイン

作りたいもの

こんな感じで、EditTextをクリックしたら生年月日を選択するためのスピナーが表示され、ユーザーが選択すると、その結果がEditTextに反映されるというような流れです。

DialogFragmentを作成

DatePickerDialogを実装するときにはDialogFragmentを作成した方がいいらしいです。
参考:選択ツール

コードはこんな感じです。

DatePickerFragment.kt
class DatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val c = Calendar.getInstance()
        val year = c.get(Calendar.YEAR)
        val month = c.get(Calendar.MONTH)
        val day = c.get(Calendar.DAY_OF_MONTH)

        var dp = DatePickerDialog(
            requireContext(),
            android.R.style.Theme_Holo_Dialog,
            this,
            year,
            month,
            day
        )

        dp.datePicker.calendarViewShown = false
        return dp
    }

    override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
        val editTxtBirthday = activity?.findViewById<EditText>(R.id.edit_txt_birthday)
        editTxtBirthday?.setText(String.format("%d/%02d/%02d", year, month+1, dayOfMonth))
    }
}

ほぼ公式ドキュメント通りですが、しいて言うなら

dp.datePicker.calendarViewShown = false

を追加しています。
もしこれがないとスピナーとカレンダーの両方が表示されてしまうので、カレンダー形式の方を削除したいという意図です。

EditTextをクリックした時の処理と連携させる

activity_input_data.xml
<EditText
     android:id="@+id/edit_txt_birthday"
     android:layout_width="match_parent"
     android:layout_height="50dp"
     android:hint="生年月日"
     android:focusable="false"
     android:inputType="date"
     android:singleLine="true" />
InputDataActivity.kt
// 生年月日を入力するeditTextをクリックしたときの処理
binding.editTxtBirthday.setOnClickListener {
     val datePicker = DatePicker(this)
     datePicker.calendarViewShown = false
     showDatePickerDialog(binding.editTxtBirthday)
}

他のやり方もあれば教えてください

これ実装してみると結構deprecatedまみれなので、他にいい実装方法があればぜひ教えていただきたい!