Jelly Bean DatePickerDialog --- キャンセルする方法はありますか? 質問する

Jelly Bean DatePickerDialog --- キャンセルする方法はありますか? 質問する

何かある奇妙なここ。

問題は、どの SDK に対してビルドするかによって決まるとは思いません。重要なのはデバイスの OS バージョンです。

問題 1: デフォルトでの不一致

DatePickerDialogJelly Beanで変更され、現在は終わりボタン。以前のバージョンではキャンセルボタンが表示されなくなり、ユーザー エクスペリエンスに影響する可能性があります (一貫性の欠如、以前の Android バージョンからの筋肉の記憶)。

複製:基本的なプロジェクトを作成します。次の場所に配置しonCreate

DatePickerDialog picker = new DatePickerDialog(
        this,
        new OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker v, int y, int m, int d) {
                Log.d("Picker", "Set!");
            }
        },
        2012, 6, 15);
picker.show();

期待される:キャンセルダイアログにボタンが表示されます。

現在:キャンセルボタンが表示されません。

スクリーンショット: 4.0.3(OK)そして4.1.1(間違っている可能性あり?)。

問題2: 不適切な却下動作

ダイアログは実際に呼び出すべきリスナーを呼び出し、その後いつもリスナーを呼び出しますOnDateSetListener。キャンセルすると set メソッドが呼び出され、設定するとメソッドが 2 回呼び出されます。

複製:#1 のコードを使用しますが、以下のコードを追加します (これにより #1 が解決されますが、視覚的/UI のみで解決されます)。

picker.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", 
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Log.d("Picker", "Cancel!");
            }
        });

期待される:

  • BACKキーを押すか、ダイアログの外側をクリックすると、何もしない
  • 「キャンセル」を押すと印刷されますピッカーをキャンセル!
  • 「設定」を押すと印刷されますピッカーセット!

現在:

  • BACKキーを押すか、ダイアログの外側をクリックすると、ピッカーセット!
  • 「キャンセル」を押すと印刷されますピッカーをキャンセル!その後ピッカーセット!
  • 「設定」を押すと印刷されますピッカーセット!その後ピッカーセット!

動作を示すログ行:

07-15 12:00:13.415: D/Picker(21000): Set!

07-15 12:00:24.860: D/Picker(21000): Cancel!
07-15 12:00:24.876: D/Picker(21000): Set!

07-15 12:00:33.696: D/Picker(21000): Set!
07-15 12:00:33.719: D/Picker(21000): Set!

その他のメモとコメント

  • それを a で囲むことはDatePickerFragment問題ではありません。私はあなたのために問題を単純化しましたが、テストしました。

ベストアンサー1

注記:Lollipopで修正されましたソースはこちら自動化クライアントで使用するクラス(すべてのAndroidバージョンと互換性あり) も更新されました。

TL;DR: グローバルなソリューションを実現する 1-2-3 の非常に簡単なステップ:

  1. ダウンロードこれクラス。
  2. OnDateSetListenerアクティビティに実装します(または、ニーズに合わせてクラスを変更します)。
  3. 次のコードでダイアログをトリガーします (このサンプルでは、​​ 内で使用しますFragment)。

    Bundle b = new Bundle();
    b.putInt(DatePickerDialogFragment.YEAR, 2012);
    b.putInt(DatePickerDialogFragment.MONTH, 6);
    b.putInt(DatePickerDialogFragment.DATE, 17);
    DialogFragment picker = new DatePickerDialogFragment();
    picker.setArguments(b);
    picker.show(getActivity().getSupportFragmentManager(), "frag_date_picker");
    

必要なのはそれだけです!私がまだ自分の回答を「承認済み」のままにしている理由は、クライアント コードのフットプリントが非常に小さく、根本的な問題 (フレームワーク クラスで呼び出されるリスナー) に対処し、構成の変更後も正常に動作し、このバグに悩まされていない以前の Android バージョンのデフォルト実装にコード ロジックをルーティングするため、依然として自分のソリューションを好んでいるからです (クラス ソースを参照)。

元の回答(歴史的および教育的な理由から保存されています):

バグソース

わかりました。確かにバグのようで、すでに誰かが修正しています。問題 34833

問題はおそらく にあることがわかりましたDatePickerDialog.java。そこには次のように書かれています:

private void tryNotifyDateSet() {
    if (mCallBack != null) {
        mDatePicker.clearFocus();
        mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(),
                mDatePicker.getMonth(), mDatePicker.getDayOfMonth());
    }
}

@Override
protected void onStop() {
    tryNotifyDateSet();
    super.onStop();
}

おそらく次のようになると思います:

@Override
protected void onStop() {
    // instead of the full tryNotifyDateSet() call:
    if (mCallBack != null) mDatePicker.clearFocus();
    super.onStop();
}

Android にパッチ/バグ レポートを提案する方法を誰かが教えてくれたら、喜んでそうします。その間、私はDatePickerDialog.java問題の添付バージョンとして、可能な修正 (シンプル) を提案しました。

バグを回避するためのコンセプト

nullコンストラクタでリスナーを設定し、BUTTON_POSITIVE後で独自のボタンを作成します。以上です。詳細は以下をご覧ください。

問題はDatePickerDialog.java、ソースを見るとわかるように、 がmCallBackコンストラクターで渡されたリスナーを格納するグローバル変数 ( ) を呼び出すために発生します。

    /**
 * @param context The context the dialog is to run in.
 * @param callBack How the parent is notified that the date is set.
 * @param year The initial year of the dialog.
 * @param monthOfYear The initial month of the dialog.
 * @param dayOfMonth The initial day of the dialog.
 */
public DatePickerDialog(Context context,
        OnDateSetListener callBack,
        int year,
        int monthOfYear,
        int dayOfMonth) {
    this(context, 0, callBack, year, monthOfYear, dayOfMonth);
}

    /**
 * @param context The context the dialog is to run in.
 * @param theme the theme to apply to this dialog
 * @param callBack How the parent is notified that the date is set.
 * @param year The initial year of the dialog.
 * @param monthOfYear The initial month of the dialog.
 * @param dayOfMonth The initial day of the dialog.
 */
public DatePickerDialog(Context context,
        int theme,
        OnDateSetListener callBack,
        int year,
        int monthOfYear,
        int dayOfMonth) {
    super(context, theme);

    mCallBack = callBack;
    // ... rest of the constructor.
}

したがって、秘訣は、nullリスナーとして保存されるリスナーを提供し、独自のボタン セットをロールすることです (以下は、#1 の元のコードを更新したものです)。

    DatePickerDialog picker = new DatePickerDialog(
        this,
        null, // instead of a listener
        2012, 6, 15);
    picker.setCancelable(true);
    picker.setCanceledOnTouchOutside(true);
    picker.setButton(DialogInterface.BUTTON_POSITIVE, "OK",
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Log.d("Picker", "Correct behavior!");
            }
        });
    picker.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", 
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Log.d("Picker", "Cancel!");
            }
        });
picker.show();

上記で投稿した可能性のある修正により、動作するようになりました。

そしてDatePickerDialog.javanullmCallbackAPI 3/1.5の時代から--- もちろん Honeycomb はチェックできませんが、例外はトリガーされません。Lollipop で問題が修正されたことを考慮すると、私はそれを調べるつもりはありません。デフォルトの実装 (私が提供したクラスでカバーされています) を使用するだけです。

最初は を呼び出さないことを恐れていましたclearFocus()が、ここでテストしたところ、ログ行はきれいでした。したがって、私が提案したその行は結局必要ではないかもしれませんが、わかりません。

以前の API レベルとの互換性(編集済み)

下のコメントで指摘したように、それはコンセプトであり、使用しているクラスをGoogle Driveアカウントからダウンロードする私が使用した方法では、バグの影響を受けないバージョンではデフォルトのシステム実装が使用されます。

クライアント クラスの定型コードを最小限に抑えたかったため、ニーズに適したいくつかの仮定 (ボタン名など) を採用しました。完全な使用例:

class YourActivity extends SherlockFragmentActivity implements OnDateSetListener

// ...

Bundle b = new Bundle();
b.putInt(DatePickerDialogFragment.YEAR, 2012);
b.putInt(DatePickerDialogFragment.MONTH, 6);
b.putInt(DatePickerDialogFragment.DATE, 17);
DialogFragment picker = new DatePickerDialogFragment();
picker.setArguments(b);
picker.show(getActivity().getSupportFragmentManager(), "fragment_date_picker");

おすすめ記事