1
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 5 years have passed since last update.

Android の DatePickerDialog で日時範囲(開始日時~終了日時)の選択

Posted at

目的

Android の DatePickerDialog を使って、日付範囲(開始日~終了日)を選択させる。

  • DatePickerDialogで日付を選んで、Buttonのtextに表示させる。
    • Buttonじゃなくて他のViewに表示させてもOK。TextViewとか。
  • 選択できる日付を制限する。
    • 開始日に終了日より後の日付を選択させない。
    • 終了日に開始日より前の日付を選択させない。

その他の仕様(詳しい説明はこちらの記事に書いてます)

すでに日付が選択されており、DatePickerDialogで日付を選ばなかったとき、選択された日付を削除する。

  • キャンセルを押したときにButton.textにセットされていた値を変更するということ。
  • ここでは日付が未入力の場合、"指定なし"というテキストをセットすることにします。

動作環境

  • Kotlin 1.3.21
  • Android 8.0 (Oreo)
  • AndroidStudio 3.3.2

動作イメージ

dataRangeTest.gif

実装

layoutファイル

開始日付と終了日付を選択・表示するButtonとTextViewの構成とします。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:context=".MainActivity">
    <TextView
            android:text="日付範囲"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:id="@+id/date_range_text"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"
            android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:layout_marginTop="16dp"/>
    <Button
            android:text="指定なし"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:id="@+id/begin_date_button"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/date_range_text" android:layout_marginLeft="64dp"
            android:layout_marginStart="64dp" android:layout_marginTop="16dp"/>
    <TextView
            android:text="~"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:id="@+id/range"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/begin_date_button" android:layout_marginLeft="8dp"
            android:layout_marginStart="8dp" android:layout_marginTop="16dp"/>
    <Button
            android:text="指定なし"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:id="@+id/end_date_button"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toEndOf="@+id/range" android:layout_marginLeft="8dp"
            android:layout_marginStart="8dp" android:layout_marginTop="16dp"/>
</android.support.constraint.ConstraintLayout>

activityファイル

以下は、MainActivity.onCreateメソッド内のコードですが、分かりやすくするために2つに分けます。

  • dateSetOnClickListener.kt : ButtonのViewを取得とButton.setOnClickListenerの実装を行う。
  • DateDialogFragment.kt : DateDialogFragmentを表示させるclass。
dateSetOnClickListener.kt
val mBeginDate = findViewById<Button>(R.id.begin_date_button)
val mEndDate = findViewById<Button>(R.id.end_date_button)

/* 開始日付を指定するボタンを押したとき */
mBeginDate.setOnClickListener {
//    DialogFragmentを生成し、表示
    DateDialogFragment(mBeginDate).show(supportFragmentManager, mBeginDate::class.java.simpleName)
}
/* 終了日付を指定するボタンを押したとき */
mEndDate.setOnClickListener {
    DateDialogFragment(mEndDate).show(supportFragmentManager, mEndDate::class.java.simpleName)
}
DateDialogFragment.kt
/* 日付を入力する時に使用するinnerクラス
   DialogFragmentで日付を入力できるカレンダーを表示する
   DialogFragmentを呼び出したボタンを取得したいので、コンストラクタの引数にButtonを定義する */
class DateDialogFragment(val button: Button) : DialogFragment() {
    /* DatePickerDialogを返却するメソッド
       このメソッドで、日付を選択した後の処理や、日付範囲、Dialogのタイトルを設定する */
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
//        現在日付を取得
        val calendar = Calendar.getInstance()
        return DatePickerDialog(
            context,
            theme,
//            DialogFragmentで日付を選択し、OKを押したときの処理
            DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
                val inputDate = Calendar.getInstance()
//                選択された日付を取得
                inputDate.set(year, month, dayOfMonth)
                val dfInputeDate = SimpleDateFormat("yyyy-MM-dd", Locale.US)
//                CalendarからStringへ変換
                val strInputDate = dfInputeDate.format(inputDate.time)
//                DialogFragmentを呼び出したボタンのテキストに日付をセット
                button.text = strInputDate
            },
            calendar.get(Calendar.YEAR),
            calendar.get(Calendar.MONTH),
            calendar.get(Calendar.DAY_OF_MONTH))
            .also {
                /* 選択可能な日付の上限を設定
                   終了日付が指定されている場合、開始日付は終了日付より後を選べないようにする */
                if (button === mBeginDate && mEndDate.text != "指定なし"){
                    val maxDate = Calendar.getInstance()
                    val dfMaxDate = SimpleDateFormat("yyyy-MM-dd", Locale.JAPAN)
//                    指定されている終了日付を取得
                    val endInputDate = dfMaxDate.parse(mEndDate.text.toString())
                    maxDate.time = endInputDate
//                    選択可能な開始日付の上限に指定されている終了日付を設定
                    it.datePicker.maxDate = maxDate.timeInMillis
                } else {
//                    選択可能な開始日付の上限に現在日付を設定
                    it.datePicker.maxDate = calendar.timeInMillis
                }
                /*  選択可能な日付の下限を指定 */
                val minDate = Calendar.getInstance()
                /* 開始日付が指定されている場合、終了日付は開始日付より前を選べないようにする */
                if (button === mEndDate && mBeginDate.text != "指定なし"){
                    val dfMinDate = SimpleDateFormat("yyyy-MM-dd", Locale.JAPAN)
                    val beginInputDate = dfMinDate.parse(mBeginDate.text.toString())
                    minDate.time = beginInputDate
//                    選択可能な終了日付の下限に指定されている開始日付を設定
                    it.datePicker.minDate = minDate.timeInMillis
                } else {
//                    選択可能な終了日付の下限を設定、ここでは2018/2/1とします
                    minDate.set(2018, 2, 1)
                    it.datePicker.minDate = minDate.timeInMillis
                }
//                タイトルが勝手に表示されるのを防ぐために空文字をセット
                it.setTitle("")
            }
    }

    /* DialogFragmentでcancelを押した際の処理 */
    override fun onCancel(dialog: DialogInterface?) {
        super.onCancel(dialog)
//        cancelを押した際はセットされていた日付を削除し、"指定なし"をセット
        button.text = "指定なし"
    }
}
1
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
1
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?