Android

DialogFragmentを自分なりに汎用的に使えるようにしてみた

More than 5 years have passed since last update.


DialogFragmentをなるだけ簡単に使いたい

ダイアログを表示したいと思い、ササーッとぐぐってみると

DialogFragmentなるものをつかってやるのがイマドキとのこと

使い方をみると、

DialogFragmentを継承してonCreateDialog()でカスタマイズするっぽい

ただ、各所で紹介されているサンプルをそのまま鵜呑みにすると

イチケースにつきイチクラスのものを作らないとイケないような感じにとれる

ただ、タイトルが違うだけのdialogを表示したいだけなのに、

都度都度、継承クラスつくって〜〜とかって…無理っす(泣)

ということで、あれこれ調べながら、汎用的に使えるdialogクラスを自分なりに作ってみた


ソース


CommonDialogFragment.java

public class CommonDialogFragment extends DialogFragment {

public interface CommonDialogInterface {
public interface onClickListener {
void onDialogButtonClick(String tag, Dialog dialog, int which);
}

public interface onShowListener {
void onDialogShow(String tag, Dialog dialog);
}

public interface onItemClickListener {
void onDialogItemClick(String tag, Dialog dialog, String title, int which);
}
}

public static final String FIELD_LAYOUT = "layout";
public static final String FIELD_TITLE = "title";
public static final String FIELD_MESSAGE = "message";
public static final String FIELD_LIST_ITEMS = "list_items";
public static final String FIELD_LIST_ITEMS_STRING = "list_items_string";
public static final String FIELD_LABEL_POSITIVE = "label_positive";
public static final String FIELD_LABEL_NEGATIVE = "label_negative";
public static final String FIELD_LABEL_NEUTRAL = "label_neutral";

private CommonDialogInterface.onShowListener mListenerShow;
private CommonDialogInterface.onClickListener mListenerOnClick;
private CommonDialogInterface.onItemClickListener mListenerItemClick;
private AlertDialog mAlertDialog;

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {

Bundle args = getArguments();

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

// listener check
if (getTargetFragment() != null) {
setListener(getTargetFragment());
} else if (getActivity() != null) {
setListener(getActivity());
}

// dialog title
if (args.containsKey(FIELD_TITLE)) {
builder.setTitle(args.getInt(FIELD_TITLE));
}

// dialog message
if (args.containsKey(FIELD_MESSAGE)) {
builder.setMessage(args.getInt(FIELD_MESSAGE));
}

// dialog customize content view
if (args.containsKey(FIELD_LAYOUT)) {
LayoutInflater inflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View content = inflater.inflate(args.getInt(FIELD_LAYOUT), null);
builder.setView(content);
}

// dialog string list
final List<String> items = new ArrayList<String>();
if (args.containsKey(FIELD_LIST_ITEMS)) {
final int[] listItems = args.getIntArray(FIELD_LIST_ITEMS);
for (int i = 0; i < listItems.length; i++) {
items.add(getString(listItems[i]));
}
}
if (args.containsKey(FIELD_LIST_ITEMS_STRING)) {
final String[] listItems = args.getStringArray(FIELD_LIST_ITEMS_STRING);
for (int i = 0; i < listItems.length; i++) {
items.add(listItems[i]);
}
}
if (items.size() > 0) {
builder.setItems(items.toArray(new String[items.size()]), new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
if ( mListenerItemClick != null) {
mListenerItemClick.onDialogItemClick(getTag(), mAlertDialog, items.get(which), which);
}
}

});
}

// positive button title and click listener
if (args.containsKey(FIELD_LABEL_POSITIVE)) {
builder.setPositiveButton(args.getInt(FIELD_LABEL_POSITIVE), new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
if (mListenerOnClick != null) {
mListenerOnClick.onDialogButtonClick(getTag(), mAlertDialog, which);
}

}
});
}

// negative button title and click listener
if (args.containsKey(FIELD_LABEL_NEGATIVE)) {
builder.setNegativeButton(args.getInt(FIELD_LABEL_NEGATIVE), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (mListenerOnClick != null) {
mListenerOnClick.onDialogButtonClick(getTag(), mAlertDialog, which);
}
}
});
}

// neutral button title and click listener
if (args.containsKey(FIELD_LABEL_NEUTRAL)) {
builder.setNeutralButton(args.getInt(FIELD_LABEL_NEUTRAL), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (mListenerOnClick != null) {
mListenerOnClick.onDialogButtonClick(getTag(), mAlertDialog, which);
}
}
});
}

// make dialog
mAlertDialog = builder.create();

// show listener
if (mListenerShow != null) {
mAlertDialog.setOnShowListener(new DialogInterface.OnShowListener() {

@Override
public void onShow(DialogInterface dialog) {
mListenerShow.onDialogShow(getTag(), mAlertDialog);
}
});
}

return mAlertDialog;
}

private void setListener(Object target) {

// on click listener
if (target instanceof CommonDialogInterface.onClickListener) {
mListenerOnClick = (CommonDialogInterface.onClickListener) target;
}

// on item click listener
if (target instanceof CommonDialogInterface.onItemClickListener) {
mListenerItemClick = (CommonDialogInterface.onItemClickListener) target;
}

// on show listener
if (target instanceof CommonDialogInterface.onShowListener) {
mListenerShow = (CommonDialogInterface.onShowListener) target;
}

}

}



なにしてるのかっていうと

titleとかmessageとかAlertDialog.Builderで設定可能なものを

Bundleつかってうけとって、それを元にdialogを作るっていう感じ。

それだけだと、ボタンとかリストのクリック判定ができないので

独自のinterfaceを作るから、呼び出しもとではそれを実装してね…と

それだけです

なので、設定可能なものを全部網羅しているわけじゃないので、

足りないものがアレば、他を真似して追加するだけで拡張は可能なはず


使い方


表示編


MainActivity.java


// title & message
private void openDialogMessageType() {
Bundle args = new Bundle();
args.putInt(CommonDialogFragment.FIELD_TITLE, R.string.app_name);
args.putInt(CommonDialogFragment.FIELD_MESSAGE, R.string.hello_world);
args.putInt(CommonDialogFragment.FIELD_LABEL_POSITIVE, android.R.string.ok);
CommonDialogFragment dialogFragment = new CommonDialogFragment();
dialogFragment.setArguments(args);
dialogFragment.show(getSupportFragmentManager(), "dialog1");
}

// original view
private void openDialogOriginalView() {
Bundle args = new Bundle();
args.putInt(CommonDialogFragment.FIELD_TITLE, R.string.app_name);
// 自分で定義したレイアウト
args.putInt(CommonDialogFragment.FIELD_LAYOUT, R.layout.dialog_prof);
args.putInt(CommonDialogFragment.FIELD_LABEL_POSITIVE, android.R.string.ok);
args.putInt(CommonDialogFragment.FIELD_LABEL_NEGATIVE, android.R.string.cancel);
CommonDialogFragment dialogFragment = new CommonDialogFragment();
dialogFragment.setArguments(args);
dialogFragment.show(getSupportFragmentManager(), "dialog2");
}

// list items
private void openDialogListItems() {
Bundle args = new Bundle();
args.putInt(CommonDialogFragment.FIELD_TITLE, R.string.app_name);
// 定義されてる文字なら
args.putIntArray(CommonDialogFragment.FIELD_LIST_ITEMS, new int[] {R.string.item1, R.string.item2});
// ソースで動的に文字列をつくるなら
args.putStringArray(CommonDialogFragment.FIELD_LIST_ITEMS_STRING, new String[] {"item a", "item b"});
args.putInt(CommonDialogFragment.FIELD_LABEL_NEGATIVE, android.R.string.cancel);
args.putInt(CommonDialogFragment.FIELD_LABEL_NEUTRAL, android.R.string.selectAll);

CommonDialogFragment dialogFragment = new CommonDialogFragment();
dialogFragment.setArguments(args);
dialogFragment.show(getSupportFragmentManager(), "dialog3");
}



基本的には

Bundleに表示したいフィールドを設定して、setArguments()で渡してあげて、表示するだけ


結果

dialog1

device-2014-04-25-022447.png

dialog2

device-2014-04-25-022641.png

dialog3

device-2014-04-25-022823.png


listener設定編

このままだと表示はできても、

ボタンをおした時とか、リストアイテムをおした時とかで

なにもアクションおこせないので、listenerを設定する

(表示するだけでいい。特になにか押されたって、アクションをこす必要なければ不要)

いまのところ、設定できるlistenerは


  • onClickListener

  • onShowListener

  • onItemClickListener

で、それぞれ


  • ボタン(positive / negative / neutral)が押下されたとき

  • dialogが表示されたとき

  • リストアイテムがクリックされたとき

に対応

実装にはinterfaceを実装するだけ


MainActivity.java

public class MainActivity extends ActionBarActivity 

implements
CommonDialogInterface.onClickListener,
CommonDialogInterface.onItemClickListener,
CommonDialogInterface.onShowListener {

/*
* 同一activityで複数のdialogを表示するときは
* tagで判断して処理を振り分けるかんじで
*/

@Override
public void onDialogButtonClick(String tag, Dialog dialog, int which) {
if ("dialog2".equals(tag)) {
// dialog 2のクリック
if (DialogInterface.BUTTON_POSITIVE == which) {
// ok ボタンがおされた
} else if (DialogInterface.BUTTON_NEGATIVE == which) {
// cancel ボタンがおされた
}
}
}

@Override
public void onDialogItemClick(String tag, Dialog dialog, String title, int which) {
// title には押されたリストアイテムのもの
// which には押されたリストアイテムのindex
if ( ! "dialog3".equals(tag)) {
return;
}
if (getString(R.string.item1).equals(title)) {
// item 1 がおされた
} else if ("item a".equals(title)) {
// item a がおされた
} else if (which == 3) {
// 4番目 item b がおされた
}
}

@Override
public void onDialogShow(String tag, Dialog dialog) {
// dialogが表示されたら
// EditTextとかで初期値を動的にやりたい場合とかに使ってる
if ( ! "dialog2".equals(tag)) {
return;
}
EditText txt = (EditText) dialog.findViewById(R.id.name);
txt.setText("hogehoge");
}

}


初期値いれたばあい

device-2014-04-25-024955.png


おわり

コレをベースに、足りないものはBundleの設定フィールドをふやしたり

listenerをふやしたりで、ある程度は網羅できそう。

ちょっとここまでやるの、大変だったけど、

これで今後は楽にできそう

Bundleを保持しておけば、同じダイアログを別々のタイミングでサクッと呼べるのもメリットですかね?

androidアプリ開発の経験は、他言語にもまして初心者なので

なにかあれば、ご指摘頂けるとと嬉しいです。


参考

ux_design_tokyoさんの[Android] DialogFragmentを使ってダイアログを表示する-Qiita