2012年8月7日火曜日

TimePickerDialogをFragmentで実装する(表示編)

チームEGGの曽川です。

ダイアログはDialogFragmentで実装することが推奨されているので、TimePickerDialogをDialogFragmentで実装しました。(こちらの記事を参考に作成しています。)
しかし記事のソースでは不完全でしたので、以下の2点をカスタマイズしています。
・外部から時間を指定可
・OSバージョンによりテーマを設定
public class TimePickerFragment extends DialogFragment implements OnTimeSetListener {

    /** 時間のキー */
    private static final String KEY_HOUR = "hour";
    /** 分のキー */
    private static final String KEY_MINUTE = "minute";

    /**
     * インスタンスを生成します。
     * 
     * @param hour
     *            時間
     * @param minute
     *            分
     * @return {@link TimePickerFragment}
     */
    public static TimePickerFragment getInstance(final int hour, final int minute) {
        final TimePickerFragment fragment = new TimePickerFragment();
        // 時間の設定
        final Bundle bundle = new Bundle();
        bundle.putInt(KEY_HOUR, hour);
        bundle.putInt(KEY_MINUTE, minute);
        fragment.setArguments(bundle);
        return fragment;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
        int theme;
        // GingerBread以前
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
            theme = android.R.style.Theme_Panel;
        } else {
            // HoneyComb以降
            theme = android.R.style.Theme_Holo_Panel;
        }
        // 12 or 24時間設定はユーザ設定に合わせる
        final Activity activity = getActivity();
        final Bundle bundle = getArguments();
        return new TimePickerDialog(activity, theme, this, bundle.getInt(KEY_HOUR), bundle.getInt(KEY_MINUTE), DateFormat.is24HourFormat(activity));
    }

    /**
     * {@inherited}
     */
    @Override
    public void onTimeSet(final TimePicker view, final int hourOfDay, final int minute) {
        // 時間の表示
        Toast.makeText(getActivity(), hourOfDay + ":" + minute, Toast.LENGTH_SHORT).show();
    }

}
まず時間の設定ですが、getInstanceで「時間」と「分」を受け取ってBundleに挿入します。
    public static TimePickerFragment getInstance(final int hour, final int minute) {
        final TimePickerFragment fragment = new TimePickerFragment();
        // 時間の設定
        final Bundle bundle = new Bundle();
        bundle.putInt(KEY_HOUR, hour);
        bundle.putInt(KEY_MINUTE, minute);
        fragment.setArguments(bundle);
        return fragment;
    }
ダイアログを作る際に時間、分をBundleから取得します。
また、DateFormat.is24HourFormatで12時間表記、24時間表記のどちらであるか、ユーザ設定を取得します。
new TimePickerDialog(activity, theme, this, bundle.getInt(KEY_HOUR), bundle.getInt(KEY_MINUTE), DateFormat.is24HourFormat(activity));
テーマ設定は、縦横切替の際に表示がおかしくなる現象が見られた(「分」の値が「時間」に設定される)のと、UIを最新のものに合わせるという2つの理由で行っています。
テーマを指定せずに縦横切替をした画面。(Nexus S[Jelly Bean])

API Level10までとそれ以降で分けています。
       // GingerBread以前
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
            theme = android.R.style.Theme_Panel;
        } else {
            // HoneyComb以降
            theme = android.R.style.Theme_Holo_Panel;
        }
TimePickerFragmentの説明は以上です。
あとは、以下の記述でダイアログを表示します。
                final Calendar calendar = Calendar.getInstance();
                TimePickerFragment.getInstance(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE)).show(getSupportFragmentManager(), "timepicker");
表示されました。

ここまで実装してきましたが、Jelly BeanとGingerBreadでonTimeSet呼び出しについていくつかの差分があります。(ICSやHoneyCombは確認できていません。)
縦横切替でonTimeSetが呼び出される(Jelly Bean)
バックキーを押すとonTimeSetが呼び出される(Jelly Bean)
完了を押すとonTimeSetが2回呼び出される
onTimeSetで重い処理を行なっていたり、キャンセルで呼び出したく場合などは少し考慮が必要です。
次回はこの問題について解決していきます。

0 件のコメント:

コメントを投稿