[解決済み] Jelly Bean DatePickerDialog --- キャンセルする方法はありますか?
質問
--- モデレーターへの注意事項 今日(7月15日)、すでにこの問題に直面している人がいることに気づきました。 こちら . しかし、私は問題についてより良い説明を提供したと思うので、これを重複として閉じることが適切であるかどうかわからない。他の質問を編集して、そこにこの内容を貼り付けるべきかどうかわかりませんが、他人の質問をあまり変えるのは気が引けます。 ---
私は何かを持っている 変 ここで
この問題は、どの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();
期待されること A キャンセル ボタンをダイアログに表示します。
現在 A キャンセル ボタンは表示されません。
スクリーンショットをご覧ください。 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キーを押すか、ダイアログの外側をクリックすると、次のようになります。 何もしない .
- キャンセル]を押すと、次のように表示されます。 ピッカーはキャンセルしてください .
- Set"を押すと、次のように表示されます。 ピッカーがセットされました .
現在
- BACKキーを押すか、ダイアログの外側をクリックすると、印刷されます。 ピッカーセット! .
- キャンセルボタンを押すと印刷されます。 ピッカーがキャンセルされました。 そして ピッカーセット! .
- Set"を押すと表示されます。 ピッカーセット! そして ピッカーセット! .
挙動を示すログ行。
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!
その他の注意事項
-
で囲むと
DatePickerFragment
は重要ではありません。問題を単純化しましたが、テストしてみました。
どのように解決するのですか?
注意 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");
そして、それだけでいいんです! 私がまだ私の回答をquot;accepted"としている理由は、クライアントコードのフットプリントが非常に小さいこと、根本的な問題(フレームワーククラスでリスナーが呼ばれること)に対処していること、設定の変更に関わらず正常に動作すること、このバグに悩まされない以前のAndroidバージョンのデフォルト実装にコードロジックをルーティングすること(クラスのソース参照)から、私がこの解決法を好むためです。
オリジナルの回答(歴史的、教訓的な理由から保管されています)。
バグ元
OK、確かにバグで、すでに誰かが埋めているようだ。 課題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
を、そこのIssueに追加してください。
不具合回避のための考え方
リスナーを設定する
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は確認できません)、例外が発生することはありません。
ロリポップが問題を修正したことを考えると、私はそれを調べるつもりはありません: ただ、デフォルトの実装(私が提供したクラスでカバーされています)を使用してください。
最初、私は
clearFocus()
しかし、ここでテストしたところ、Logの行はきれいでした。だから、私が提案した行は、結局必要ないかもしれませんが、私は知りません。
以前の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");
関連
-
ジャークとして。起動アクティビティを特定できませんでした。デフォルトのアクティビティが見つかりません アクティビティ起動中のエラー
-
android E/RecyclerView﹕ アダプタが接続されていないため、レイアウトをスキップする。
-
エラーが発生しました。ArrayAdapter は、リソース ID が TextView である必要があります。
-
Google PlayデバイスはPlay保護機構の認証を受けていません。
-
android block certificate validation CertPathValidatorException: 認証パスのトラストアンカーが見つかりません
-
android exception - aapt.exe has stopped working.
-
超シンプルなアンドロイドのタイムディレイ機能
-
アプリの実行エラー。ターゲットデバイスが見つからない問題
-
[解決済み] AndroidでPythonを実行する方法はありますか?
-
[解決済み] APKファイルからソースコードを取得する方法はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Android Studio を 3.6.3 にアップデートした後、構成 :classpath のアーティファクトをすべて解決できない。
-
ジャークとして。起動アクティビティを特定できませんでした。デフォルトのアクティビティが見つかりません アクティビティ起動中のエラー
-
アンドロイドスタジオでJunitのエラー問題を解決する
-
例外「指定された子にはすでに親がいます」の解決方法。removeViewを呼び出す必要があります" の解決方法(ソースコード付き例)
-
Android Nで報告されたエラーを解決する: android.os.FileUriExposedException: file:///storage/emulated/0/
-
Android TextViewにandroid:ellipsize=endのバグがある。
-
WeChatとQQは、他のアプリのオープンリストに自分のアプリを追加し、ファイルパスを取得することができます
-
view.getRootView()の本当の意味とテストについて
-
SpinnerのOnItemSelectedListenerのonItemSelectedメソッドの4つのパラメーターの意味
-
android.content.ActivityNotFoundException を解決します。Intent問題を処理するActivityが見つからない