こんにちは、新米Androidエンジニアの鶴田です。DialogFragmentを使ってダイアログ上に色々なViewを管理していると色々上手くいかないことが多くなってきました。今回はDialogFragmentから脱却し、Fragmentで仮ダイアログを実装した経緯とその利点を紹介したいと思います。

問題が発生した経緯

ダイアログから画面遷移を行い、戻ってきたときに遷移前と同じ状態のViewを表示しようとしました。(編集中のEditTextなどの状態を保持する)これはただ単にダイアログの上に、FragmentTransaction#add()で上にフラグメントを乗せてしまえば済む話だと考えていたのですが、ダイアログは常に最前面に配置されるのでフラグメントが隠れてしまいます。そこで以下のパターンを検討してみました。
① DialogFragmentをFragmentTransaction#hide()で隠し、戻ってきた際にFragmentTransaction#show()で再度表示する。
② DialogをDialog#hide()で隠し、戻ってきた際にDialog#show()で再度表示する。

※フラグメントそのものを隠すか、フラグメントが持っているダイアログを隠すかの違いです。

結論から言うと①は失敗、②は成功しました。
①はどうやらFragmentTransaction#hide()はDialogFragmentには効果が無いみたいです。DialogFragmentはFragmentを継承しているので実行はされますが、何も起こりませんでした。
②のパターンはうまくいきましたが・・・Dialog#hide()でダイアログを隠し、アプリをバックグラウンドへ移動させ、再度アプリをフォアグラウンドへ移動させると、隠していたダイアログが何故か表示されていました。。。

原因を調べてみましたが、それらしき文献は見当たらなかったです。この動作によって意図しない画面遷移などでアプリが落ちてしまう可能性がでてきたので、②も無しとなりました。
ここでDialogFragmentから脱却することを決意・・・!

DialogFragmentから脱却する利点

もうDialogFragmentの限界だと見切りをつけ、Fragmentで仮ダイアログを作ることにしました。今回の問題然り、そもそもAndroidのデフォルトダイアログは微妙なところが多いです。上にフラグメントを乗せられないとか、画面サイズの変更がめんどくさいとか...。Fragmentでダイアログを作る最大のメリットは、Fragmentごとでダイアログを管理できることです。例えば親FragmentがFragmnetTransaction#remove()されれば、その子Fragmentも一緒にremoveしてくれます。DialogFragmentのダイアログは、FragmentTransactionの操作の干渉を受けないので画面の管理がしずらいです。

Fragment DialogFragment
Screenshot_1519896488 Screenshot_1519896486

Fragmentでダイアログを作成した画面が左の画像です。右のDialogFragmentで作成したものと比べるとあまり違いはないと思います。半透明の背景の上にViewを置くだけでダイアログっぽくなります。ダイアログの画面サイズも柔軟に変更できます。ただ背景タップでダイアログを閉じたい場合は、自分でその処理を実装する必要があるので注意です。

おわりに

DialogFragmentのダイアログの利用は、操作の簡単な確認(はい,いいえの選択)や、入力ツールの表示(日付ダイアログなど)の場合にとどめておくべきかなと思いました。画面遷移や多機能な実装が入ってくると、DialogFragmentで管理するのが難しくなってくるので今回のようにFragmentで仮のダイアログを作ってみてください。

© 2018. SuperSoftware Co., Ltd. All Rights Reserved.