LoginSignup
5
4

More than 1 year has passed since last update.

【Android】初心者向け シンプルなドラムロール式DatePickerサンプル

Last updated at Posted at 2022-01-03

Android開発初心者の私はシンプルなドラムロール式のDatePickerを実装しようとした時に、意外と複数のサイトを参照しながら試行錯誤しました。
同じような初心者の方の参考になれば幸いです。

ドラムロール式DatePickerのイメージ

Screenshot_1641257836.png

2a1aee80cd619115f682e1a0b162a90d.gif

サンプルの仕様

・日付入力欄は直接日付を入力することもできる。
・入力欄が空白など日付として認識できない場合、初期値として今日がDatePickerに表示される。
・入力欄が日付の場合、DatePickerには入力欄の日付が初期表示される。
・DatePickerで選択した日付が入力欄に反映される。

サンプルの仕様変更(2022年1月6日)

■ 古い仕様 ・日付入力欄をクリックするとドラムロール式DatePickerが表示される。

■ 変更後の仕様 ※ 日付入力欄のどこをクリックしてもDatePickerを表示する仕様だとうざったいので仕様変更 ・日付入力欄はクリックしてもなにも起こらない。 ・下向き矢印を入力欄とは独立したImageViewにし、下向き矢印をクリックした時だけDatePickerを表示する。

環境

android studio arctic fox | 2020.3.1 patch 4
compileSdk 32

コード

さっそくコードの主要部分を紹介します。
ここではわかり易さを重視して必要な部分のコードのみ抜粋しています。
ソース全体は https://github.com/masayahak/Datepicker へアップしています。

DatePickerを呼び出すアクティビティ

Screenshot_1641260151.png

activity_main.xml
    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/date_label"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="販売開始日"
        app:startIconDrawable="@drawable/ic_calendar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/date"
            android:layout_width="190dp"
            android:layout_height="60dp"
            android:inputType="date"
            android:clickable="false"
            />
    </com.google.android.material.textfield.TextInputLayout>

    <!-- DatePicker表示ボタン -->
    <ImageButton
        android:id="@+id/date_picker_actions"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:contentDescription="DatePicker"
        android:src="@drawable/ic_arrow_down"
        app:layout_constraintTop_toTopOf="@id/date_label"
        app:layout_constraintBottom_toBottomOf="@id/date_label"
        android:layout_marginTop="4dp"
        app:layout_constraintEnd_toEndOf="@id/date_label"
        android:layout_marginEnd="8dp"
        app:tint="@android:color/black"
        android:background="@color/white"
        />

日付入力欄としてTextInputEditTextを利用し、android:clickable="false"にしました。
DatePickerダイアログを表示するのはImageButtonが担当しています。
ImageButtonのandroid:src="@drawable/ic_arrow_down"は下向きの矢印アイコンです。
クリックでDatePickerダイアログが表示されることを明示するためのアイコンです。

MainActivity.kt
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val img = findViewById<ImageView>(R.id.date_picker_actions)
        img.setOnClickListener {
            // ドラムロール式DatePickerを呼び出す
            val eText = findViewById<View>(R.id.date) as EditText
            MyDatePicker.showDatePicker(eText)
        }
    }

MyDatePicker.showDatePickerで汎用化したDatePickerダイアログを呼び出しています。
引数へDatePickerが値を受け渡しする日付入力用のEditTextを渡してます。

汎用化したDatePicker

MyDatePicker.kt
@RequiresApi(Build.VERSION_CODES.O)
object MyDatePicker {

    fun showDatePicker (eText : EditText) {

        // 日付入力フィールドが空白など日付ではないときの初期値として、「今日」を設定
        val defaultDate = LocalDate.now()
        var year = defaultDate.year
        var monthValue = defaultDate.monthValue
        var dayOfMonth = defaultDate.dayOfMonth

        // 日付入力フィールドの値が日付の場合はその値を設定
        val ldt = toLocaleDate(eText.text.toString())
        if (ldt != null) {
            year = ldt.year
            monthValue = ldt.monthValue
            dayOfMonth = ldt.dayOfMonth
        }

        // ドラム式DatePicker表示
        val picker = DatePickerDialog(
            eText.rootView.context,
            AlertDialog.THEME_HOLO_LIGHT,   // テーマ:ドラム式 背景白

            // ダイアログでOKをクリックされたときの処理 日付入力フィールドへ値を設定
            { _, getYear, getMonthOfYear, getDayOfMonth
                -> eText.setText(String.format("%d/%02d/%02d",
                getYear,
                getMonthOfYear + 1,     // 月はZEROオリジン
                getDayOfMonth))
            },

            // DatePickerが初期表示する日付
            year,
            monthValue - 1, // 月はZEROオリジン
            dayOfMonth
        )
        picker.show()

    }

    private const val DATE_FORMAT = "yyyy/MM/dd"

    fun toLocaleDate(stringDate : String) : LocalDate? {
        val df = DateTimeFormatter.ofPattern(DATE_FORMAT)
        return try { LocalDate.parse(stringDate, df) } catch (t: Throwable) { null }
    }

}

終わりに

非常に短いコードですが、1つずつ調べながら手作りするのは大変ですよね。お役に立てれば幸いです。
コメント、質問も歓迎です。

5
4
3

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
5
4