何かある奇妙なここ。
問題は、どの SDK に対してビルドするかによって決まるとは思いません。重要なのはデバイスの OS バージョンです。
問題 1: デフォルトでの不一致
DatePickerDialog
Jelly 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 の非常に簡単なステップ:
- ダウンロードこれクラス。
OnDateSetListener
アクティビティに実装します(または、ニーズに合わせてクラスを変更します)。次のコードでダイアログをトリガーします (このサンプルでは、 内で使用します
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.java
、null
(mCallback
API 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");