marunomaruno-memo

marunomaruno-memo

Android ダイアログ (6) 日付と時間の選択ダイアログ その2/2

2011年08月22日 | Android
ダイアログ (5) 日付と時間の選択ダイアログ その2
================================================================================

■時刻の選択ダイアログ

時刻を選択するダイアログは、TimePickerDialog を使う。
とくに何もしなくても、タイトルや選択するボタンなどは、日本語で表示してくれる。
また、DatePickerDialog と違って、時刻のタイトルは、mm:dd の形式なので、とくに変
更する必要はない。


□ Dialog08Activity.java
---
package jp.marunomaruno.android.sample;

import java.util.Calendar;

import android.app.Activity;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.TimePicker;

public class Dialog08Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        TextView date = (TextView) findViewById(R.id.date);

        Calendar calendar = Calendar.getInstance();
        int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);

        TimePickerDialog dialog = new TimePickerDialog(this,
                new DateSetHandler(date), hourOfDay, minute, true);    // (1)
        dialog.show();
    }

    private class DateSetHandler implements TimePickerDialog.OnTimeSetListener { // (2)
        private TextView date;

        public DateSetHandler(TextView date) {
            this.date = date;
        }

        @Override
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // (3)
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
            calendar.set(Calendar.MINUTE, minute);

            date.setText(String.format(getString(R.string.time_format), calendar));
        }
    }
}
---

□ TimePickerDialog dialog = new TimePickerDialog(this,
                new DateSetHandler(date), hourOfDay, minute, true);    // (1)

時刻を設定する TimePickerDialog オブジェクトを生成する。
このとき、時刻が設定されたときのリスナー、最初に表示される時・分を指定する。

・クラス階層
java.lang.Object
   + android.app.Dialog
         + android.app.AlertDialog
               + android.app.TimePickerDialog

・主なコンストラクター
---
TimePickerDialog(Context context, TimePickerDialog.OnTimeSetListener callBack, 
                    int hourOfDay, int minute, boolean is24HourView)
TimePickerDialog(Context context, int theme, 
                    TimePickerDialog.OnTimeSetListener callBack, 
                    int hourOfDay, int minute, boolean is24HourView)
---

時刻が設定されたときのリスナーのオブジェクトや、最初に表示される時刻、24時間表示
にするかどうかを引数として渡す。


□ private class DateSetHandler implements TimePickerDialog.OnTimeSetListener { // (2)

時刻が設定されたときのリスナー TimePickerDialog.OnTimeSetListener の実装クラスを
定義する。


□ TimePickerDialog.OnTimeSetListener

時刻が設定されたときのリスナーのインターフェース。

実装すべきメソッドは以下のメソッド。
abstract void  onTimeSet(TimePicker view, int hourOfDay, int minute)


□ public void onTimeSet(TimePicker view, int hourOfDay, int minute) {    // (3)

時刻が設定されたときのハンドラー・メソッド。
変更された時刻は、引数の hourOfDay, minute に入っている。

※
---
onDateSet() もそうだが、view から、設定されている時刻を取得できるので、引数の 
hourOfDay, minute はいらないと思うが、どうなんだろう。
単に使いやすさのためかな。
---

□ values/strings.xml
---

<resources>
    <string name="hello">Hello World, Dialog08Activity!</string>
    <string name="app_name">Dialog08</string>
    <string name="time_format">%tR</string>
</resources>
---


■日付と時刻の選択ダイアログ

このサンプルは、日時を指定するのではなく、日付と日時をそれぞれ、別のダイアログで
指定するもの。べつべつに指定したものをリスナーでまとめている。

□ Dialog09Activity.java
---
package jp.marunomaruno.android.sample;

import java.util.Calendar;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.widget.DatePicker;
import android.widget.TextView;
import android.widget.TimePicker;

public class Dialog09Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        TextView date = (TextView) findViewById(R.id.date);

        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int monthOfYear = calendar.get(Calendar.MONTH);
        int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
        int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);

        TimePickerDialog timePickerDialog = new TimePickerDialog(this,
                new DateSetHandler(date), hourOfDay, minute, true);     // (1)
        timePickerDialog.show();

        DatePickerDialog datePickerDialog = new DatePickerDialog(this,
                new DateSetHandler(date), year, monthOfYear, dayOfMonth); // (2)
        datePickerDialog.show();

    }

    private class DateSetHandler implements DatePickerDialog.OnDateSetListener,
            TimePickerDialog.OnTimeSetListener {                        // (3)
        private TextView date;
        private Calendar calendar = Calendar.getInstance();             // (4)

        public DateSetHandler(TextView date) {
            this.date = date;
        }

        @Override
        public void onDateSet(DatePicker view, int year, int monthOfYear,
                int dayOfMonth) {                                       // (5)
            calendar.set(year, monthOfYear, dayOfMonth);                // (6)

            date.setText(String.format(getString(R.string.date_time_format),
                    calendar));                                         // (7)
        }

        @Override
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // (8)
            calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);              // (9)
            calendar.set(Calendar.MINUTE, minute);                      // (10)

            date.setText(String.format(getString(R.string.date_time_format),
                    calendar));                                         // (11)
        }
    }
}
---

□ TimePickerDialog timePickerDialog = new TimePickerDialog(this,
                new DateSetHandler(date), hourOfDay, minute, true);       // (1)
□ DatePickerDialog datePickerDialog = new DatePickerDialog(this,
                new DateSetHandler(date), year, monthOfYear, dayOfMonth); // (2)

日付、時刻の順で設定するので、ダイアログは、TimePickerDialog、DatePickerDialog 
の順番に表示する。
表示するのが時刻、日付の順番でよいので、実は生成の順番はこのとおりでなくてもよい。


□ private class DateSetHandler implements DatePickerDialog.OnDateSetListener,
            TimePickerDialog.OnTimeSetListener {                         // (3)

日時の変更に対処するために、DatePickerDialog.OnDateSetListener と、TimePickerDia
log.OnTimeSetListener の 2 つのインターフェースを実装するリスナーのクラスをつく
る。


□ private Calendar calendar = Calendar.getInstance();                  // (4)

onDateSet() メソッドと、onTimeSet() メソッドの2つで使うので、インスタンス変数と
して定義する。


□ public void onDateSet(DatePicker view, int year, int monthOfYear,
                int dayOfMonth) {                                      // (5)
□ calendar.set(year, monthOfYear, dayOfMonth);                        // (6)

日付が設定されたときのメソッド。ここで、calendar に日付部分を設定する。


□ date.setText(String.format(getString(R.string.date_time_format), calendar)); 
                                                                         // (7)
□ date.setText(String.format(getString(R.string.date_time_format), calendar)); 
                                                                         // (11)

設定された日時をテキストビューに設定する。フォーマットは以下のとおり。
    <string name="date_time_format">%1$tF %1$tR</string>
すなわち、
    yyyy-mm-dd hh:mm

※補足
---
今回のサンプルでは使用していないが、2 つ以上の書式指示子を指定する場合、引数の位
置(argument_index$)を指定する必要がある。そうしないと、つぎの strings.xml では、
次のエラーになり、プロジェクトのビルドができない。
Multiple annotations found at this line:
    - error: Multiple substitutions specified in non-positional format; did you 
      mean to add the formatted="false" attribute?
    - error: Unexpected end tag string

また、直接、Java ソースで指定すると、実行時のエラーとなる。

このことからも、文字列リテラルは直接ソース上でハードコーディングせずに、
strings.xml などのリソースとして定義しておいたほうがよい。

なお、この仕様は Android の仕様で、Java の仕様ではない。Java の場合は、引数の位
置を指定しないときは、引数が順番に割り振られる。
---


□ public void onTimeSet(TimePicker view, int hourOfDay, int minute) { // (8)
□ calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);                      // (9)
□ calendar.set(Calendar.MINUTE, minute);                              // (10)

時刻が設定されたときのメソッド。ここで、calendar に時刻部分を設定する。


□ values/strings.xml
---

<resources>
    <string name="hello">Hello World, Dialog09Activity!</string>
    <string name="app_name">Dialog09</string>
    <string name="date_time_format">%1$tF %1$tR</string>
</resources>
---


■ 日時を同時に指定するダイアログ

日付と日時をべつべつのダイアログで設定するのではなく、ひとつのダイアログにまとめ
て設定する。これも、カスタムダイアログになるので、ダイアログのクラスは 
AlertDialog を使う。
カスタムビューとしては、DatePicker と TimePicker を LinearLayout で組み合わせた
ものを使う。

□ Dialog091Activity.java
---
package jp.marunomaruno.android.sample;

import java.util.Calendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.DatePicker;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TimePicker;

public class Dialog091Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // 結果を設定するビューを取得する
        TextView date = (TextView) findViewById(R.id.date);

        // ダイアログに表示する日時を取得する
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int monthOfYear = calendar.get(Calendar.MONTH);
        int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
        int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);

        // 2つのpickerを併せたビューを作る
        DatePicker datePicker = new DatePicker(this);                   // (1)
        TimePicker timePicker = new TimePicker(this);                   // (2)

        LinearLayout view = new LinearLayout(this);                     // (3)
        view.setOrientation(LinearLayout.VERTICAL);                     // (4)
        view.addView(datePicker);                                       // (5)
        view.addView(timePicker);                                       // (6)

        // 日時を設定するビューを使ったダイアログを生成する
        AlertDialog dialog = new AlertDialog.Builder(this)              // (7)
                .setView(view)                                          // (8)
                .setTitle(
                        String.format(getString(R.string.date_time_format),
                                calendar, calendar))
                .setPositiveButton(R.string.set_title, new DateSetHandler(view,
                                date))                                  // (9)
                .setNegativeButton(R.string.cancel_title, null).show();

        // pickerに値が変化したことを検知するハンドラーを設定する
        DateChangedHandler handler = new DateChangedHandler(dialog);    // (10)

        datePicker.init(year, monthOfYear, dayOfMonth, handler);        // (11)
        timePicker.setCurrentHour(hourOfDay);                           // (12)
        timePicker.setCurrentMinute(minute);                            // (13)
        timePicker.setOnTimeChangedListener(handler);                   // (14)
        timePicker.setIs24HourView(true);                               // (15)
    }

    /**
     * 日時が変更されたときの処理をするハンドラー
     */
    private class DateChangedHandler implements
            DatePicker.OnDateChangedListener, TimePicker.OnTimeChangedListener {
        private AlertDialog dialog;
        private Calendar calendar = Calendar.getInstance();

        public DateChangedHandler(AlertDialog dialog) {
            this.dialog = dialog;
        }

        @Override
        public void onDateChanged(DatePicker view, int year, int monthOfYear,
                int dayOfMonth) {
            calendar.set(year, monthOfYear, dayOfMonth);

            Log.d("TEST", String.format("d: %tc", calendar));

            dialog.setTitle(String.format(getString(R.string.date_time_format),
                    calendar));
        }

        @Override
        public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
            calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
            calendar.set(Calendar.MINUTE, minute);

            Log.d("TEST", String.format("t: %tc", calendar));

            dialog.setTitle(String.format(getString(R.string.date_time_format),
                    calendar));
        }
    }

    /**
     * 日時が設定されたときの処理をするハンドラー
     */
    private class DateSetHandler implements DialogInterface.OnClickListener { // (16)
        private ViewGroup view;
        private TextView date;

        public DateSetHandler(ViewGroup view, TextView date) {
            this.view = view;
            this.date = date;
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {        // (17)
            DatePicker datePicker = (DatePicker) view.getChildAt(0);    // (18)
            TimePicker timePicker = (TimePicker) view.getChildAt(1);    // (19)
            
            Calendar calendar = Calendar.getInstance();
            calendar.set(datePicker.getYear(), datePicker.getMonth(),
                    datePicker.getDayOfMonth(), timePicker.getCurrentHour(),
                    timePicker.getCurrentMinute());

            Log.d("TEST", String.format("s: %tc", calendar));

            date.setText(String.format(getString(R.string.date_time_format),
                    calendar));
        }
    }
}
---

□ DatePicker datePicker = new DatePicker(this);                   // (1)
□ TimePicker timePicker = new TimePicker(this);                   // (2)

カスタムビューとして作るために、DatePicker、TimePicker のオブジェクトを生成する。
2 つのビューなので、これを、つぎの LinearLayout にまとめて、たてに 2 つのピッ
カーが表示されるようにする。

DatePicker については既出。

TimePicker は、日時を設定できるビューのクラス。

・クラス階層
java.lang.Object
   + android.view.View
         + android.view.ViewGroup
               + android.widget.FrameLayout
                     + android.widget.TimePicker

・コンストラクター
---
TimePicker(Context context)
TimePicker(Context context, AttributeSet attrs)
TimePicker(Context context, AttributeSet attrs, int defStyle)
---


□ LinearLayout view = new LinearLayout(this);                     // (3)
□ view.setOrientation(LinearLayout.VERTICAL);                     // (4)
□ view.addView(datePicker);                                       // (5)
□ view.addView(timePicker);                                       // (6)

DatePicker、TimePicker のオブジェクトを 2 つ縦に並べるレイアウトとして、LinearLa
yout オブジェクトを生成し、たてに設定して、DatePicker、TimePicker のオブジェクト
を追加する。
なお、LinearLayout は、ViewGroup のサブクラスになっているので、つぎのメソッドで、
ビューを追加できる。

ViewGroup の addView() メソッド
---
void     addView(View child, int index, ViewGroup.LayoutParams params)
void     addView(View child, ViewGroup.LayoutParams params)
void     addView(View child, int index)
void     addView(View child)
void     addView(View child, int width, int height)
---

引数 index を指定しないものでは、(おそらく) 0 から順番にindex が振られて追加され
る。


□ AlertDialog dialog = new AlertDialog.Builder(this)           // (7)
□ .setView(view)                                               // (8)

カスタムダイアログとして、AlertDialog オブジェクトを生成し、LinearLayout のオブ
ジェクトをカスタムビューとして設定する。


□ .setPositiveButton(R.string.set_title, new DateSetHandler(view, date)) // (9)

設定ボタンを設定する。リスナーのオブジェクトは、DialogInterface.OnClickListener 
を実装する。


□ DateChangedHandler handler = new DateChangedHandler(dialog);    // (10)

日時を変えることに対するリスナーのオブジェクトを生成する。
このオブジェクトは、DatePicker と TimePicker オブジェクトの初期化のところで使用
する。


□ datePicker.init(year, monthOfYear, dayOfMonth, handler);        // (11)
□ timePicker.setCurrentHour(hourOfDay);                           // (12)
□ timePicker.setCurrentMinute(minute);                            // (13)
□ timePicker.setOnTimeChangedListener(handler);                   // (14)
□ timePicker.setIs24HourView(true);                               // (15)

現在日時と、(10) で作った日時を変えることに対するリスナーのオブジェクトを使って、
DatePicker と TimePicker オブジェクトを初期化する。
初期化には、DatePicker クラスでは、次のメソッドを使う。
void  init(int year, int monthOfYear, int dayOfMonth, 
                DatePicker.OnDateChangedListener onDateChangedListener)

また、TimePicker クラスでは、次のメソッド。なぜか、init メソッドがない。ちょっと
不思議な感じ。
void  setCurrentHour(Integer currentHour)
void  setCurrentMinute(Integer currentMinute)
void  setOnTimeChangedListener(TimePicker.OnTimeChangedListener 
                                                        onTimeChangedListener)
void  setIs24HourView(Boolean is24HourView)

TimePicker のデフォルトの表示形式は、12 時間表示になっているので、
setIs24HourView(true) を指定しないと、24 時間表示にはならない。


□ private class DateSetHandler implements DialogInterface.OnClickListener { // (16)
□ public void onClick(DialogInterface dialog, int which) {        // (17)

設定ボタンに対するリスナーの実装クラスと、そのハンドラーメソッド。


□ DatePicker datePicker = (DatePicker) view.getChildAt(0);    // (18)
□ TimePicker timePicker = (TimePicker) view.getChildAt(1);    // (19)

このクラスには、日時の設定ダイアログで使ったビュー(ViewGroup の型で、実際のオブ
ジェクトは LinearLayout)を渡している。
そのビューのオブジェクトから、そこに設定しているそれぞれのピッカーのオブジェクト
を取得する。

・ViewGroup で、子ビューを取得するメソッド
---
View  getChildAt(int index)
---

index は、addView() メソッドで指定した順番。


□ values/strings.xml
---

<resources>
    <string name="hello">Hello World, Dialog091Activity!</string>
    <string name="app_name">Dialog091</string>
    <string name="date_format">%tF</string>
    <string name="time_format">%tR</string>
    <string name="date_time_format">%1$tF %1$tR</string>
</resources>
---

                                                                        以上


最新の画像もっと見る

コメントを投稿