こんにちは、コンテンツクリエイターのともすけです。
この記事の内容は、初心者向けよりすこし難しいです。
Androidアプリを作る際に使用する部品の1つにTimePickerDialogがあります。後半で具体的な記述例を示しますので、お急ぎの方は下の方へスクロールしてください。
それってどういうやつなの?
これです。
時間を指定して分を指定して、OKを押して使います。ですが…問題が。
何が問題なの?
Android Developerサイトにサンプルが書かれているのですが、設定した値を取り込む方法が書かれていません。つまりはこういうこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { <em>// Use the current time as the default values for the picker </em>final Calendar c = Calendar.getInstance(); int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); <em>// Create a new instance of TimePickerDialog and return it </em>return new TimePickerDialog(getActivity(), this, hour, minute, DateFormat.is24HourFormat(getActivity())); } public void onTimeSet(TimePicker view, int hourOfDay, int minute) { <em>// Do something with the time chosen by the user </em>} } |
*Android Developerサイトから引用
この記述をTimePickerDialog.javaとしてプロジェクトに組み込み、
1 2 3 4 |
public void showTimePickerDialog(View v) { DialogFragment newFragment = new TimePickerFragment(); newFragment.show(getSupportFragmentManager(), "timePicker"); } |
*Android Developerサイトから引用
をプログラム上で呼び出せばいいと書いてあります。呼び出すと、先程の画面が表示されます。入力を終えてOKを押すと、onTimeSetメソッドが呼び出されます。サンプルコードにも、英語で何かをしてねと書かれています。そう、ここに書けというんです。
で、何が問題なの?
設定された値をどうやって呼び出し元のclassに渡すか。ウェブ上に点在する記事によれば、どれもログを表示するとか、その程度の実用レベルとは程遠い例しかないんです。表示するだけでは意味がないんです。制御に使えないと意味がないんです…。
何か対策はないの?
SharedPreferencesを使おうかとも思いましたが、これは値を書き込んだ後すぐに反映されない場合があって、そのため呼び出し元ですぐにリードすると設定した値が読めないことが多々あります。
いろいろ調べたり考えたりして、1つ気がついたことがありました。
1 2 |
return new TimePickerDialog(getActivity(), this, hour, minute, DateFormat.is24HourFormat(getActivity())); |
第2引数がthisなんですけど、これはlistener型なんです。listenerって、これのことです。
1 2 |
public class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener { |
二行目に、OnTimeSetListenerと書かれています。このように書くと、時間設定が終わってOKが押されたときに
1 2 3 |
public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // Do something with the time chosen by the user } |
が呼び出されるということなんです。
うんうん、それで?
Dialogのclassにlistenerを記述しないで、呼び出し元に定義し、それを指定すればいいということなんです。つまり、Dialogのclass記述は結果的には
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class TimePickerFragment extends DialogFragment <em>/*implements TimePickerDialog.OnTimeSetListener*/ </em>{ @Override public Dialog onCreateDialog(Bundle savedInstanceState) { <em>// Use the current time as the default values for the picker </em>final Calendar c = Calendar.getInstance(); int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); <em>// Create a new instance of TimePickerDialog and return it /*return new TimePickerDialog(getActivity(), this, hour, minute, DateFormat.is24HourFormat(getActivity()));*/ </em>return new TimePickerDialog(getActivity(), (RegisterActivity) getActivity(), hour, minute, DateFormat.is24HourFormat(getActivity())); } <em>/*public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // Do something with the time chosen by the user }*/ </em>} |
となります。修正内容は、
- listenerを他で定義するので、implementsの行はコメントアウト
- returnの行で、第2引数がthisとなっていたところは(RegisterActivity)getActivity()となります。RegisterActivityは、TimePickerDialogを呼び出す元のActivityです。呼び出し元は人によって違うので、参考程度としてください。
- 呼び出し元のActivityにimplements…の行を追加して、public void onTimeSet(上に書いてあった定義)を追加し、その中に適切な記述を書きます。
こうすると、呼び出し元で設定された値を取得できるので、その値を使って各種制御に使えることになります。
そっかー、そういうことなんだね!(わかったつもり)
いかがでしょうか。ポイントは、Dialogを定義するclassの中にlistenerを設定せず、呼び出し元のclassに定義して呼び出すことです。
MainActivityのサンプルを掲載しておきますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.DialogFragment; import android.app.TimePickerDialog; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TimePicker; import android.widget.Toast; public class MainActivity extends AppCompatActivity implements TimePickerDialog.OnTimeSetListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout baseLayout = new LinearLayout(this); baseLayout.setOrientation(LinearLayout.<em>VERTICAL</em>); Button button = new Button(this); baseLayout.addView(button); setContentView(baseLayout); button.setText("ダイアログを表示"); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showTimePickerDialog(v); } }); } public void showTimePickerDialog(View v) { DialogFragment newFragment = new TimerPickerFragment(); newFragment.show(getSupportFragmentManager(), "timePicker"); } @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { Toast.<em>makeText</em>(getApplicationContext(), String.<em>format</em>("%d時%d分がセットされました。", hourOfDay, minute), Toast.<em>LENGTH_SHORT</em>).show(); } } |
それではまた