DialogFragmentの使い方

執筆中

DialogFragmentを利用するときのチェックポイント

Activityにレイアウトを準備せずに使えるDialogFragmentは使いやすい。
ただ最初は少し癖があるので、要点をおさらいしておくとよい。
そんなTopicをご提供。

参考にするリンク

名前
URL

基本的な作り方

まずは基本的な作り方から。
1度見ておけばそうそう間違わないことから、ついやってしまうことまで挙げていく。

publicなクラスで作成する

DialogFragmentは必ず public なクラスでなければならない。
なぜなら configChanges や onRestart が起こる際に再描画で呼ばれるので、
ActivityManager(の呼び先)がインスタンスの生成を行える必要があるからである。

まぁ、Activity を「class MyActivity extends Activity」で作るのと同じことだ。
実際に呼び出しが掛かるのは android.app あたりのパッケージなので、
どうしても見えないとインスタンス生成できないってことになる。

ありがちなのは「private static final class」にしてしまうことだな!
私もよくやってしまう。慣れるとそうでもないんだが。
リソースや表示のテストの観点も考えると、いっそのことDialogFragmentは同じパッケージに置けばいい。
com.test.main.MyActivity.java
com.test.dialog.MyDialogFragment.java
的な。

デフォルトコンストラクタを作っておく

初回起動データを渡すためにコンストラクタに引数を入れるのはいいが、必ずデフォルトコンストラクタを作っておくこと。
でないとConfigurationChangedが起きたあとにエラーが発生する。

こんな風にしていると・・・
  1. public class TestDialog extends DialogFragment {
  2.  
  3. int messageId;
  4.  
  5. public TestDialog(int resId) {
  6. messageId = resId;
  7. }
  8.  
縦横切り替えしたらこんなエラーがでる。
make sure class name exists, is public, and has an empty constructor that is public
デフォルトコンストラクタ無いと画面復帰できないんだけど?って感じ。


後述する public static final void show(FragmentManager manager) を作っておけば、
そちらで Fragment#setArguments() ができるのでデータ受け渡しの心配もない。
  1. public class TestDialog extends DialogFragment {
  2.  
  3. public static final void show(FragmentManager manager, int resId) {
  4. L.std();
  5. TestDialog dialog = new TestDialog();
  6. Bundle args = new Bundle();
  7. args.putInt("RESID", resId);
  8. dialog.setArguments(args);
  9. dialog.show(manager, TestDialog.class.getSimpleName());
  10. }
  11. ~~~
  12.  

メンドウなときは以下のようにしてしまうがな!
  1. public class TestDialog extends DialogFragment {
  2.  
  3. int messageRes;
  4.  
  5. public static final void show(FragmentManager manager, int resId) {
  6. L.std();
  7. TestDialog dialog = new TestDialog();
  8. dialog.messageRes = resId;
  9. dialog.show(manager, TestDialog.class.getSimpleName());
  10. }
  11. ~~~
  12.  

public static final void show(FragmentManager manager)を提供する

これは必須ではない。
しかし、複数の画面にDialogを提供する可能性が高いDialogFragmentである。
手続きを1箇所にすることで簡素化を図るとともに、
データの受け渡しを制限することでカプセル化を行っておきたい。
また必要に応じて hide(or close), update を提供するのもよいと思う。

  1. public class TestDialog extends DialogFragment {
  2.  
  3. private static final String TAG = TestDialog.class.getSimpleName();
  4.  
  5. public static final void show(FragmentManager manager) {
  6. L.std();
  7. TestDialog dialog = new TestDialog();
  8. dialog.show(manager, TAG);
  9. }
  10.  
  11. public static final void update(FragmentManager manager) {
  12. // 更新処理は必ずここを通るので、処理が散見しなくていいね。
  13. Fragment temp = manager.findFragmentByTag(TAG);
  14. // このチェックはシステム上不要なら null チェックで十分。
  15. // 今回は掲載用に instanceof なんて使ってます。
  16. if (temp instanceof TestDialog) {
  17. TestDialog dialog = (TestDialog) temp;
  18.  
  19. // タイトル変更、ChoicePosition調整、リストデータ更新、etc...
  20. dialog.getDialog().setTitle("変更!");
  21. }
  22. }
  23.  
  24. public static final void hide(FragmentManager manager) {
  25. Fragment temp = manager.findFragmentByTag(TAG);
  26. if (temp instanceof TestDialog) {
  27. TestDialog dialog = (TestDialog) temp;
  28. dialog.dismiss();
  29. }
  30. }
  31. ~~~
  32.  

表示スタイル

DialogFragment#setStyle() は表示するダイアログの見た目を変える。
注意して欲しいのは、Dialogの画面生成が行われる onCreateDialog() までの間に行う必要があること。
onCreateView()では遅すぎるので注意しよう。

オススメは DialogFragment の new 時点で入れてしまうこと。
データを覚えるために setArguments() を行うついでに入れてしまおう。


第一引数はDialogの表示項目+αの設定で、
STYLE_NORMAL
いつものダイアログ画面
STYLE_NO_TITLE
タイトルが表示されない。
STYLE_NO_FRAME
タイトルが表示されないどころか、設定したViewの大きさで形が自由自在。
STYLE_NO_INPUT
見た目はSTYLE_NO_FRAMEで、キー入力などのイベントが一切来ない。

といった感じ。
特に STYLE_NO_FRAME は優秀で、onCreateView()で返したViewが適用されるので非常に広い領域が使える。
ViewGroupのツリーは
  1. DecorView
    1. FrameLayout
      1. FrameLayout(android.R.id.content)
        1. onCreateView()で返したView
      2. ViewStub(android.R.id.action_mode_bar_stub)
となるので、作るときは <merge> を使いたくなるが、
onCreateView() の ViewGroup container が null だと落ちることになる。
ので素直にRelativeLayoutとか使おう。

onCreateDialog()とonCreateView()の違い

onCreateDialog()の実装例

onCreateView()の実装例

少し拡張する

コンテキストメニューを出す

オプションメニューを出す

DialogFragmentのオプションメニューを出すには、Dialog側のMenu関連メソッドをオーバーライドする必要がある。

特殊な使い方

レイアウトにFragmentを入れる場合の注意

PreferenceFragmentを表示する

ListFragmentを表示する


まとめ

関連リンク

&trackback()
タグ一覧:Android DialogFragment Fragment Fragment Note 執筆中



最終更新:2012年11月17日 00:13