上記を大変参考にさせて頂いて実装を開始した。メッセージとOK/NGのコールバックだけあれば、ダイアログは生きていける。
ただ、場合によってメッセージだけじゃなくてEditTextを表示する必要がある場合があった。もちろんsetItemsしたい時もあった。こうなるとOK/NGだけでは生きていけない。
とりえあずsetViewを上記のコードに含み入れたものがこちら。無理やり感あるけど、まぁ別Fragmentにする理由もなかった。
public class ShowDialogFragment extends DialogFragment{ private DialogListener listener = null; /** * ファクトリーメソッド * @param type ダイアログタイプ 0:OKボタンのみ 1:OK, NGボタン */ public static ShowDialogFragment newInstance(String title, String message,int type,int viewId){ ShowDialogFragment instance = new ShowDialogFragment(); // ダイアログに渡すパラメータはBundleにまとめる Bundle arguments = new Bundle(); arguments.putString("title", title); arguments.putString("message", message); arguments.putInt("type", type); arguments.putInt("viewId", viewId); instance.setArguments(arguments); return instance; } /** * AlertDialog作成 */ @Override public Dialog onCreateDialog(Bundle savedInstanceState){ String title = getArguments().getString("title"); String message = getArguments().getString("message"); int type = getArguments().getInt("type"); //Viewを初期化する int viewId = getArguments().getInt("viewId"); LayoutInflater inflater = getActivity().getLayoutInflater(); final View view = inflater.inflate(viewId, null, false); AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()) .setTitle(title) .setMessage(message) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { listener.doPositiveClick(view); dismiss(); } }); if (type == 1){ alert.setNegativeButton("キャンセル", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { listener.doNegativeClick(view); dismiss(); } }); } //超強引 if(viewId != R.layout.empty) alert.setView(view); return alert.create(); } /** * リスナーを追加 */ public void setDialogListener(DialogListener listener){ this.listener = listener; } @Override public void onDetach() { super.onDetach(); if(listener !=null) listener = null; } } //Listener import android.view.View; import java.util.EventListener; public interface DialogListener extends EventListener { /** * OKボタンが押されたイベントを通知 */ void doPositiveClick(View view); /** * Cancelボタンが押されたイベントを通知 */ void doNegativeClick(View view); }
inflateする時は必ずXMLファイルが必要になる
viewのオブジェクトを外から与えるには、layoutInflatorを使ってres/layoutのxmlのIDを与えるしか方法がない。で、それをsetView()。適当な数字を入れてinflateするとResourceNotFoundExceptionが発生するので、setViewする必要がないダイアログでも適当なlayoutのxml指定が必要になった。空レイアウトしかないempty.xmlを作った。
空レイアウトをそのままsetViewするとマージンが取られてしまい、ダイアログのメッセージとボタンの間に変な間が開いてしまう。ソースを追うのもめんどいので、argument経由で渡したviewIdがemptyのものじゃなければsetViewするというやり方を取った。
emptyだったらviewを初期化しなくても良いじゃないと一瞬思ったけど、クロージャのコールバックに渡す時はfinal修飾子をつけねばならない制約があるため、常にinflateするようにした。ちょっとオーバーヘッド。
使い方は下記の通り。上記のコードと大差ない。引数にviewのIdが増え、リスナーのコールバックにsetViewしたレイアウトがそのまま引数として渡る。setViewしたviewの状態をコールバックで拾えるので、ほとんどこれで行けるやろ。
ShowDialogFragment f = ShowDialogFragment.newInstance( "カートの保存", "現在のカートの状態を名前をつけて保存します。", 1,R.layout.dialog_save_cart ); f.setDialogListener(new DialogListener() { @Override public void doPositiveClick(View view) { EditText t =(EditText)view.findViewById(R.id.dialog_save_cart_name); Log.d("DEBUG",t.getText().toString()); } @Override public void doNegativeClick(View view) { //do nothing. } }); f.show(getFragmentManager(), "dialog");
が、setItemsの場合は、OK/NGだけじゃなくて、ListのItemClickリスナーが別途必要になる。ActionSheet的に使うこともあれば、複数チェックしたものを画面に返したい時もあるだろう。こうなるとわけがわからなくなりそうなので、setItemsしたいDialogFragmentは別のクラスに起こそうと思っています。