こんな感じでしょうか。
まず、 MainViewModel
は、 DatePicker と TimePicker で入力された日付時刻を保持することに専念(_dateTimeStr
)します。_dateTimeStr
には、DatePicker の onDateChanged、 TimePicker の onTimeChanged を素直に受信して、それらから YYYYMMDDHHMM な文字列を設定します(※YYYYMMDDHHMMな文字列にしたのはデバッグが分かりやすかっただけです、ミリ秒とか Date/Calendar クラスでもよいと思います。)。
次に TwoWay Binding はやめて、 _dateTimeStr
から 年月日と時刻それぞれの ReadonlyRxProperty
を生成し、OneWay で DatePicker と TimePicker にバインドさせます。
最後に、ボタンを押した時に、その時点での現在日時を保存しておき(_savedCurrentDateTime
)、ボタンのタイトルや使用可否は、保存された現在日時とDatePicker+TimePickerで入力された日時が一致しているかどうかで定義された ReadOnlyRxProperty として用意します。
データバインドする ReadOnlyRxProperty は全て _dateTimeStr
から生成しているので、 _dateTimeStr
が変われば連動して変化するのをイメージすると分かりやすいと思います。
そして _dateTimeStr
を変化させるのは DatePicker/TimePicker を操作した時、またはボタンを押したとき、です。
MainViewModel.kt
kotlin
1package nakasho.github.io.datepickersample
2
3import android.arch.lifecycle.ViewModel
4import android.text.TextUtils
5import android.util.Log
6import jp.keita.kagurazaka.rxproperty.RxProperty
7import jp.keita.kagurazaka.rxproperty.toReadOnlyRxProperty
8import java.util.*
9
10class MainViewModel : ViewModel() {
11 private var _savedCurrentDateTime: String = "" // ボタン押下時の現在日時を保存(YYYYMMDDHHMM)
12 private val _dateTimeStr = RxProperty<String>() // DatePicker+TimePicker に表示する日付文字列(YYYYMMDDHHMM)
13
14 private var _buttonTapped: Boolean = false // 現在時刻ボタンが押されたらtrueに
15
16 // YYYYMMDDHHMM から各成分に該当する桁を数値に変換してバインディング用の RxProperty とする
17 val year = _dateTimeStr.map { dt -> dt.substring(0, 4) }.map { it->it.toInt() }.toReadOnlyRxProperty()
18 val month = _dateTimeStr.map { dt -> dt.substring(4, 6) }.map { it->it.toInt() - 1 }.toReadOnlyRxProperty() // month は 0 始まりなので
19 val day = _dateTimeStr.map { dt -> dt.substring(6, 8) }.map { it->it.toInt() }.toReadOnlyRxProperty()
20 val hour = _dateTimeStr.map { dt -> dt.substring(8, 10) }.map { it->it.toInt() }.toReadOnlyRxProperty()
21 val minute = _dateTimeStr.map { dt -> dt.substring(10, 12) }.map { it->it.toInt() }.toReadOnlyRxProperty()
22
23 // 現在時刻ボタンが押され、ボタン押下時の現在日時と DatePicker+TimePickerの日時が同じなら現在時刻設定中であり enabled=false とする
24 val buttonEnabled = _dateTimeStr.map { dt -> !_buttonTapped && !TextUtils.equals(dt, _savedCurrentDateTime) }.toReadOnlyRxProperty()
25 val buttonText = buttonEnabled.map { enable -> if (enable) "現在日時を設定" else "現在時刻設定中" }.toReadOnlyRxProperty()
26
27 init {
28 _dateTimeStr.set("201712312345") // DatePicker+TimePickerの既定値(YYYYMMDDHHMM)
29 }
30
31 //Pickerを現在時刻に設定する
32 //onClickが発生したら実行
33 fun tapButton() {
34 _buttonTapped = true
35 val cal = Calendar.getInstance()
36 val dateTimeStr = String.format("%4d%02d%02d%02d%02d",
37 cal.get(Calendar.YEAR),
38 cal.get(Calendar.MONTH) + 1, // month は 0 始まりなので
39 cal.get(Calendar.DAY_OF_MONTH),
40 cal.get(Calendar.HOUR),
41 cal.get(Calendar.MINUTE))
42 _savedCurrentDateTime = dateTimeStr
43 _dateTimeStr.set(dateTimeStr)
44 }
45
46 fun changeDate(year:Int, monthIndex:Int, day:Int) {
47 val dateStr = String.format("%4d%02d%02d", year, monthIndex+1, day) // month は 0 始まりなので
48 Log.d("MainViewModel", "changeDate ${dateStr} finished")
49
50 // 日付部を変更して更新
51 var dateTimeStr = _dateTimeStr.get()
52 _dateTimeStr.set(dateStr + dateTimeStr.substring(8))
53 }
54
55 fun changeTime(hour:Int, minute:Int) {
56 val timeStr = String.format("%02d%02d", hour, minute)
57 Log.d("MainViewModel", "changeTime ${timeStr} finished")
58
59 // 時刻部を変更して更新
60 var dateTimeStr = _dateTimeStr.get()
61 _dateTimeStr.set(dateTimeStr.substring(0, 8) + timeStr)
62 }
63}
activity_main.xml
xml
1<?xml version="1.0" encoding="utf-8"?>
2<layout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools">
5 <data>
6 <variable
7 name="viewModel"
8 type="nakasho.github.io.datepickersample.MainViewModel"/>
9 </data>
10
11 <android.support.constraint.ConstraintLayout
12 android:layout_width="match_parent"
13 android:layout_height="match_parent"
14 tools:context="nakasho.github.io.datepickersample.MainActivity">
15 <DatePicker
16 android:id="@+id/datePicker"
17 android:layout_width="wrap_content"
18 android:layout_height="wrap_content"
19 android:calendarViewShown="false"
20 android:datePickerMode="spinner"
21 android:spinnersShown="true"
22 android:year="@{viewModel.year.value}"
23 android:month="@{viewModel.month.value}"
24 android:day="@{viewModel.day.value}"
25 android:onDateChanged="@{(view, year, month, day)-> viewModel.changeDate(year, month, day)}"
26 app:layout_constraintLeft_toLeftOf="parent"
27 app:layout_constraintRight_toRightOf="parent"
28 app:layout_constraintTop_toTopOf="parent"/>
29
30 <TimePicker
31 android:id="@+id/timePicker"
32 android:layout_width="wrap_content"
33 android:layout_height="wrap_content"
34 android:timePickerMode="spinner"
35 android:hour="@{viewModel.hour.value}"
36 android:minute="@{viewModel.minute.value}"
37 android:onTimeChanged="@{(view, hour, minute)-> viewModel.changeTime(hour, minute)}"
38 app:layout_constraintLeft_toLeftOf="parent"
39 app:layout_constraintRight_toRightOf="parent"
40 app:layout_constraintTop_toBottomOf="@id/datePicker" />
41
42 <Button
43 android:id="@+id/button"
44 android:layout_width="wrap_content"
45 android:layout_height="wrap_content"
46 android:text="@{viewModel.buttonText.value}"
47 android:onClick="@{()-> viewModel.tapButton()}"
48 android:enabled="@{viewModel.buttonEnabled.value}"
49 app:layout_constraintLeft_toLeftOf="parent"
50 app:layout_constraintRight_toRightOf="parent"
51 app:layout_constraintTop_toBottomOf="@id/timePicker"
52 app:layout_constraintBottom_toBottomOf="parent"/>
53</android.support.constraint.ConstraintLayout>
54</layout>
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/16 03:21
2018/01/16 03:53
2018/01/16 11:03