2013年9月6日金曜日

DialogFragmentでのカスタムダイアログ実装方法

DialogFragmentによるカスタムダイアログ実装方法について、下記の点をまとめておく。お題としてパズドラ風のダイアログを実装してみる。
  • 基本
  • コンテンツ部分
  • スタイル
完成形

基本

DialogFragmentを継承したpublicクラスを作成する。注意点は下記の通り。

  • ファクトリーメソッド(下記例ではnewInstance())を用意する。
  • コンストラクタのオーバーロードを作らない、使わない
  1. public class MyDialogFragment extends DialogFragment  
  2. {  
  3.   /** 
  4.    * ファクトリーメソッド 
  5.    */  
  6.   public static MyDialogFragment newInstance(String param)  
  7.   {  
  8.     MyDialogFragment instance = new MyDialogFragment();  
  9.   
  10.     // ダイアログに渡すパラメータはBundleにまとめる  
  11.     Bundle arguments = new Bundle();  
  12.     arguments.putString("parameter", param);  
  13.   
  14.     instance.setArguments(arguments);  
  15.     return instance;  
  16.   }  
  17. }  

コンテンツ部分(お手軽パターン)

コンテンツ部分の実装は、onCreateDialog()やonCreateView()をオーバーライドして行う。 お手軽パターンでは、onCreateDialog()のみをオーバーライドして、必要な機能を有するDialogインスタンスを生成する。

  1. /** 
  2.  * ダイアログコンテナを生成する。 
  3.  */  
  4. @Override  
  5. public Dialog onCreateDialog(Bundle b)  
  6. {  
  7.   // ダイアログのコンテンツ部分  
  8.   LayoutInflater i  
  9.     = (LayoutInflater) getActivity()  
  10.         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  11.   View content = i.inflate(R.layout.mydialog_content, null);  
  12.   
  13.   AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());  
  14.   
  15.   // タイトル  
  16.   builder.setTitle("My Custom Dialog");  
  17.   // コンテンツ  
  18.   builder.setView(content);  
  19.   // OK  
  20.   builder.setPositiveButton(android.R.string.ok, null);  
  21.   
  22.   Dialog dialog = builder.create();  
  23.   
  24.   // ダイアログ外タップで消えないように設定  
  25.   dialog.setCanceledOnTouchOutside(false);  
  26.   
  27.   return dialog;  
  28. }  
  • 「お手軽」ではあるが、埋め込み部品として再利用(レイアウトの一部として配置)することができないデメリットがある。
  • HoneyComb以降は、ダイアログ外タップで閉じるのがデフォルトなので注意。

コンテンツ部分(お上品パターン)

お上品パターンでは、onCreateDialog()でダイアログコンテナを生成し、onCreateView()でコンテンツを生成する。OKボタンなどはレイアウトで、ダイアログの見栄えは後述のスタイルで賄う。

  1. /** 
  2.  * ダイアログコンテナを生成する。 
  3.  */  
  4. @Override  
  5. public Dialog onCreateDialog(Bundle b)  
  6. {  
  7.   Dialog dialog = super.onCreateDialog(b);  
  8.   
  9.   // タイトル  
  10.   dialog.setTitle("My Custom Dialog");  
  11.   // ダイアログ外タップで消えないように設定  
  12.   dialog.setCanceledOnTouchOutside(false);  
  13.   
  14.   return dialog;  
  15. }  
  16.   
  17. /** 
  18.  * UIを生成する。 
  19.  */  
  20. @Override  
  21. public View onCreateView(LayoutInflater i, ViewGroup c, Bundle b)  
  22. {  
  23.   View content = i.inflate(R.layout.mydialog_content, null);  
  24.   return content;  
  25. }  
  • onCreateDialog()をオーバーライドしつつ、onCreateView()でnull以外を返すとAndroidRuntimeExceptionが発生する…と読めるような情報もあるが、AlertDialog使用方法の問題でありDialogFragment固有の問題では無い (AlertDialogを使わなければ良い)

コンテンツのレイアウト

ここでは、前述のお上品パターンで利用するレイアウト(ボタンも含める)を想定し、下図のようなレイアウトを作成する。RelativeLayoutを利用することで、ダイアログをお好みの位置に表示する。(下記例では画面下部に配置)

このレイアウトのコードは以下の通り。
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout  
  3.   xmlns:android="http://schemas.android.com/apk/res/android"  
  4.   android:layout_width="match_parent"  
  5.   android:layout_height="match_parent" >  
  6.   
  7.   <LinearLayout  
  8.     android:layout_width="match_parent"  
  9.     android:layout_height="wrap_content"  
  10.     android:layout_alignParentBottom="true"  
  11.     android:layout_margin="10dp"  
  12.     android:background="@drawable/dialog_bg"  
  13.     android:gravity="center_horizontal"  
  14.     android:orientation="vertical"  
  15.     android:paddingBottom="10dp"  
  16.     android:paddingLeft="10dp"  
  17.     android:paddingRight="10dp"  
  18.     android:paddingTop="20dp" >  
  19.   
  20.     <TextView  
  21.         android:layout_width="match_parent"  
  22.         android:layout_height="match_parent"  
  23.         android:layout_margin="10dp"  
  24.         android:background="#d595c2d7"  
  25.         android:minLines="7"  
  26.         android:text="以上の内容で送信してよろしいですか?"  
  27.         android:textColor="@android:color/black" />  
  28.   
  29.     <Button  
  30.         android:id="@android:id/button1"  
  31.         android:layout_width="wrap_content"  
  32.         android:layout_height="35sp"  
  33.         android:background="@drawable/button_bg"  
  34.         android:minWidth="100dp"  
  35.         android:text="@android:string/ok"  
  36.         android:textColor="@android:color/white"  
  37.         android:textSize="22sp"  
  38.         android:textStyle="bold" />  
  39.     </LinearLayout>  
  40. </RelativeLayout>  
さらに、ダイアログ背景をXMLで作成する。
drawable/dialog_bg_part1.xml(白枠だけの画像)
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android" >  
  3.   <corners android:radius="10dp" />  
  4.   <stroke  
  5.     android:width="2dp"  
  6.     android:color="#ffffff" />  
  7. </shape>  
drawable/dialog_bg_part2(黒枠にグラデーション塗りつぶしの画像)
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android" >  
  3.   <corners android:radius="10dp" />  
  4.   <gradient  
  5.     android:angle="270"  
  6.     android:endColor="#f1114461"  
  7.     android:startColor="#f13c91ba" />  
  8.   <stroke  
  9.     android:width="1dp"  
  10.     android:color="#000000" />  
  11. </shape>  
drawable/dialog_bg.xml(合体)
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  
  3.   <item android:drawable="@drawable/dialog_bg_part1"/>  
  4.   <item  
  5.     android:bottom="2dp"  
  6.     android:drawable="@drawable/dialog_bg_part2"  
  7.     android:left="2dp"  
  8.     android:right="2dp"  
  9.     android:top="2dp"/>  
  10. </layer-list>  
ボタンの背景画像も同様に作成する
drawable/button_bg.xml
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <shape xmlns:android="http://schemas.android.com/apk/res/android" >  
  3.   <corners android:radius="10dp" />  
  4.   <gradient  
  5.     android:angle="270"  
  6.     android:endColor="#222656"  
  7.     android:startColor="#6a75c7" />  
  8.   <stroke  
  9.     android:width="1px"  
  10.     android:color="#0c2446" />  
  11. </shape>  

スタイル

最後に、背景(前項キャプチャの黒いところ)やタイトル(前項キャプチャのvalueと書いてあるとこ)を消して、ダイアログの表示アニメーションを制御するためにスタイルを定義および適用する。

values/styles.xml
Androidのダイアログテーマを拡張し、タイトル指定・背景・アニメーションの設定を上書きする。

  1. <!-- タイトル無し、背景透明、アニメーション指定 -->  
  2. <style name="Theme.MyDialog" parent="@android:style/Theme.Dialog">  
  3.   <item name="android:windowNoTitle">true</item>  
  4.   <item name="android:windowBackground">@android:color/transparent</item>  
  5.   <item name="android:windowAnimationStyle">@style/Animation.MyDialog</item>  
  6. </style>  

ウィンドウアニメーションスタイルは下記の通り定義する。表示する時のアニメーション(windowEnterAnimation)と消える時のアニメーション(windowExitAnimation)をそれぞれ指定。

  1. <style name="Animation.MyDialog" parent="android:Animation.Dialog">  
  2.   <item name="android:windowEnterAnimation">@anim/options_panel_enter</item>  
  3.   <item name="android:windowExitAnimation">@anim/options_panel_exit</item>  
  4. </style>  

アニメーション定義

anim/options_panel_enter.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android"  
  3.   android:interpolator="@android:anim/decelerate_interpolator" >  
  4.   <translate  
  5.     android:duration="@android:integer/config_shortAnimTime"  
  6.     android:fromYDelta="25%"  
  7.     android:toYDelta="0" />  
  8.   <alpha  
  9.     android:duration="@android:integer/config_shortAnimTime"  
  10.     android:fromAlpha="0.0"  
  11.     android:toAlpha="1.0" />  
  12. </set>  

anim/options_panel_exit.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android"  
  3.   android:interpolator="@android:anim/accelerate_interpolator" >  
  4.   <translate  
  5.     android:duration="@android:integer/config_shortAnimTime"  
  6.     android:fromYDelta="0"  
  7.     android:toYDelta="50%" />  
  8.   <alpha  
  9.     android:duration="@android:integer/config_shortAnimTime"  
  10.     android:fromAlpha="1.0"  
  11.     android:toAlpha="0.0" />  
  12. </set>  

DialogFragmentのonCreate()をオーバーライドして、スタイルを適用するコードを記述する。

  1. /** 
  2.  * フラグメント生成コールバックメソッド 
  3.  */  
  4. @Override  
  5. public void onCreate(Bundle b)  
  6. {  
  7.   super.onCreate(b);  
  8.   
  9.   setStyle(DialogFragment.STYLE_NORMAL, R.style.Theme_MyDialog);  
  10. }  

おしまい


参考サイト

0 件のコメント:

コメントを投稿