2013/11/08

DialogFragment のイベントを Activity とか Fragment に伝えたい。

削除しますか?「はい/いいえ」の確認ダイアログ出して、「はい」したらもとの画面からも消えてるみたいな。ダイアログのイベントを元々の画面伝えたい。そんな感じのよくある話。

DialogFragment になにか渡したいときは Fragment の特徴である DialogFragment#setArguments() で渡さないといけない。でもリスナー渡したいときは一筋縄ではいかない。DialogFragment#setOnDoSomethingListener() なんかを生やしても大人の事情でダメ。ここでこうやってみる。

まずはなんにせよ Listener を作る。
public class ConfirmDialogFragment extends DialogFragment {
public interface OnButtonClickListener {
public void onPositiveClick();
public void onNegativeClick();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

こんな感じ。

Activity に通知する場合。


Activity にリスナーを implements するの忘れない。Dialog 側は onAttach(Activity activity) をオーバーライドする。ライフサイクルに組み込まれてるこのメソッドでは Activity が渡されるので、そのアクティビティが Listener を implements してるかチェックできる。なので DialogFragment#setArguments() で渡さなくてもいい。
// DialogFragment
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
this.mOnDialogButtonClickListener = (OnDialogButtonClickListener)activity;
} catch (ClassCastException e) {
e.printStackTrace();
}
}
view raw gistfile3.java hosted with ❤ by GitHub

こんな感じ。あとは必要なところでthis.mOnDialogButtonClickListenerのメソッド使えばいい。

Fragment に通知する場合。


DialogFragment にいつもの newInstance() を生やす。ここで引数に Fragment をとるようにして、DialogFragment#setTargetFragment() を使って Fragment を保持。必要なときに DialogFragment#getTargetFragment() から Fragment を取ってきてリスナーにキャストして使う。ちょっと回りくどい。

public class ConfirmDialogFragment extends DialogFragment implements
DialogInterface.OnClickListener {
public interface OnDialogButtonClickListener {
public void onPositiveClick();
public void onNegativeClick();
}
public static ConfirmDialogFragment newInstance(Fragment fragment) {
ConfirmDialogFragment dialog = new ConfirmDialogFragment();
dialog.setTargetFragment(fragment, 0);
return dialog;
}
@Override
public void onClick(DialogInterface dialog, int which) {
OnDialogButtonClickListener listener;
try {
listener = (OnDialogButtonClickListener) this.getTargetFragment();
} catch (ClassCastException e) {
// リスナーなし
return;
}
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
listener.onPositiveClick();
break;
case DialogInterface.BUTTON_NEGATIVE:
listener.onNegativeClick();
break;
}
}
view raw gistfile4.java hosted with ❤ by GitHub

こんな感じでいいんじゃまいか。