欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android 官方推荐 : DialogFragment 怎样创建对话框

来源: 开发者 投稿于  被查看 34224 次 评论:169

Android 官方推荐 : DialogFragment 怎样创建对话框


1、 概述
DialogFragment在android 3.0时被引入。是一种特殊的Fragment,用于在Activity的内容之上展示一个模态的对话框。典型的用于:展示警告框,输入框,确认框等等。
在DialogFragment产生之前,我们创建对话框:一般采用AlertDialog和Dialog。注:官方不推荐直接使用Dialog创建对话框。
2、 好处与用法
使用DialogFragment来管理对话框,当旋转屏幕和按下后退键时可以更好的管理其声明周期,它和Fragment有着基本一致的声明周期。且DialogFragment也允许开发者把Dialog作为内嵌的组件进行重用,类似Fragment(可以在大屏幕和小屏幕显示出不同的效果)。上面会通过例子展示这些好处~

使用DialogFragment至少需要实现onCreateView或者onCreateDIalog方法。onCreateView即使用定义的xml布局文件展示Dialog。onCreateDialog即利用AlertDialog或者Dialog创建出Dialog。

3、 重写onCreateView创建Dialog

a)布局文件,我们创建一个设置名称的布局文件:

 

[html]view plaincopy
 
 
 
  1.  
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content">
  4.  
  5. android:id="@+id/id_label_your_name"
  6. android:layout_width="wrap_content"
  7. android:layout_height="32dp"
  8. android:gravity="center_vertical"
  9. android:text="Yourname:"/>
  10.  
  11. android:id="@+id/id_txt_your_name"
  12. android:layout_width="match_parent"
  13. android:layout_height="wrap_content"
  14. android:layout_toRightOf="@id/id_label_your_name"
  15. android:imeOptions="actionDone"
  16. android:inputType="text"/>
  17.  
  18. android:id="@+id/id_sure_edit_name"
  19. android:layout_width="wrap_content"
  20. android:layout_height="wrap_content"
  21. android:layout_alignParentRight="true"
  22. android:layout_below="@id/id_txt_your_name"
  23. android:text="ok"/>
  24.  
  25.  

    b)继承DialogFragment,重写onCreateView方法

     

     

    [java]view plaincopy
     
     
     
    1. packagecom.example.zhy_dialogfragment;
    2.  
    3. importandroid.app.DialogFragment;
    4. importandroid.os.Bundle;
    5. importandroid.view.LayoutInflater;
    6. importandroid.view.View;
    7. importandroid.view.ViewGroup;
    8.  
    9. publicclassEditNameDialogFragmentextendsDialogFragment
    10. {
    11.  
    12.  
    13. @Override
    14. publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
    15. BundlesavedInstanceState)
    16. {
    17. Viewview=inflater.inflate(R.layout.fragment_edit_name,container);
    18. returnview;
    19. }
    20.  
    21. }
       

      c)测试运行:

       

      Main方法中调用:

       

      [java]view plaincopy
       
       
       
      1. publicvoidshowEditDialog(Viewview)
      2. {
      3. EditNameDialogFragmenteditNameDialog=newEditNameDialogFragment();
      4. editNameDialog.show(getFragmentManager(),"EditNameDialog");
      5. }
         
        效果图:

         

         

        \
        可以看到,对话框成功创建并显示出来,不过默认对话框有个讨厌的标题,我们怎么去掉呢:可以在onCreateView中调用getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);即可去掉。即:
        [java]view plaincopy
         
         
        1. publicclassEditNameDialogFragmentextendsDialogFragment
        2. {
        3.  
        4. @Override
        5. publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
        6. BundlesavedInstanceState)
        7. {
        8. getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
        9. Viewview=inflater.inflate(R.layout.fragment_edit_name,container);
        10. returnview;
        11. }
        12.  
        13. }
           

          效果图:
           
          \
          很完美的去掉了讨厌的标题。
           
          4、 重写onCreateDialog创建Dialog
          在onCreateDialog中一般可以使用AlertDialog或者Dialog创建对话框,不过既然google不推荐直接使用Dialog,我们就使用AlertDialog来创建一个登录的对话框。

           

          a)布局文件

           

          [html]view plaincopy
           
           
           
          1.  
          2. android:layout_width="wrap_content"
          3. android:layout_height="wrap_content"
          4. android:orientation="vertical">
          5.  
          6. android:layout_width="match_parent"
          7. android:layout_height="64dp"
          8. android:background="#FFFFBB33"
          9. android:contentDescription="@string/app_name"
          10. android:scaleType="center"
          11. android:src="@drawable/title"/>
          12.  
          13. android:id="@+id/id_txt_username"
          14. android:layout_width="match_parent"
          15. android:layout_height="wrap_content"
          16. android:layout_marginBottom="4dp"
          17. android:layout_marginLeft="4dp"
          18. android:layout_marginRight="4dp"
          19. android:layout_marginTop="16dp"
          20. android:hint="inputusername"
          21. android:inputType="textEmailAddress"/>
          22.  
          23. android:id="@+id/id_txt_password"
          24. android:layout_width="match_parent"
          25. android:layout_height="wrap_content"
          26. android:layout_marginBottom="16dp"
          27. android:layout_marginLeft="4dp"
          28. android:layout_marginRight="4dp"
          29. android:layout_marginTop="4dp"
          30. android:fontFamily="sans-serif"
          31. android:hint="inputpassword"
          32. android:inputType="textPassword"/>
          33.  
          34.  

            b)继承DialogFragment重写onCreateDialog方法

             

             

            [java]view plaincopy
             
             
             
            1. packagecom.example.zhy_dialogfragment;
            2.  
            3. importandroid.app.AlertDialog;
            4. importandroid.app.Dialog;
            5. importandroid.app.DialogFragment;
            6. importandroid.content.DialogInterface;
            7. importandroid.os.Bundle;
            8. importandroid.view.LayoutInflater;
            9. importandroid.view.View;
            10. importandroid.view.ViewGroup;
            11. importandroid.widget.EditText;
            12.  
            13. publicclassLoginDialogFragmentextendsDialogFragment
            14. {
            15.  
            16. @Override
            17. publicDialogonCreateDialog(BundlesavedInstanceState)
            18. {
            19. AlertDialog.Builderbuilder=newAlertDialog.Builder(getActivity());
            20. //Getthelayoutinflater
            21. LayoutInflaterinflater=getActivity().getLayoutInflater();
            22. Viewview=inflater.inflate(R.layout.fragment_login_dialog,null);
            23. //Inflateandsetthelayoutforthedialog
            24. //Passnullastheparentviewbecauseitsgoinginthedialoglayout
            25. builder.setView(view)
            26. //Addactionbuttons
            27. .setPositiveButton("Signin",
            28. newDialogInterface.OnClickListener()
            29. {
            30. @Override
            31. publicvoidonClick(DialogInterfacedialog,intid)
            32. {
            33. }
            34. }).setNegativeButton("Cancel",null);
            35. returnbuilder.create();
            36. }
            37. }
               

              c)调用

               

               

              [java]view plaincopy
               
               
               
              1. publicvoidshowLoginDialog(Viewview)
              2. {
              3. LoginDialogFragmentdialog=newLoginDialogFragment();
              4. dialog.show(getFragmentManager(),"loginDialog");
              5. }
                 

                效果图:

                 

                \

                 

                可以看到通过重写onCreateDialog同样可以实现创建对话框,效果还是很nice的。

                5、传递数据给Activity

                从dialog传递数据给Activity,可以使用“fragment interface pattern”的方式,下面通过一个改造上面的登录框来展示这种模式。

                改动比较小,直接贴代码了:

                 

                [java]view plaincopy
                 
                 
                 
                1. packagecom.example.zhy_dialogfragment;
                2.  
                3. importandroid.app.AlertDialog;
                4. importandroid.app.Dialog;
                5. importandroid.app.DialogFragment;
                6. importandroid.content.DialogInterface;
                7. importandroid.os.Bundle;
                8. importandroid.view.LayoutInflater;
                9. importandroid.view.View;
                10. importandroid.view.ViewGroup;
                11. importandroid.widget.EditText;
                12.  
                13. publicclassLoginDialogFragmentextendsDialogFragment
                14. {
                15. privateEditTextmUsername;
                16. privateEditTextmPassword;
                17.  
                18. publicinterfaceLoginInputListener
                19. {
                20. voidonLoginInputComplete(Stringusername,Stringpassword);
                21. }
                22.  
                23. @Override
                24. publicDialogonCreateDialog(BundlesavedInstanceState)
                25. {
                26. AlertDialog.Builderbuilder=newAlertDialog.Builder(getActivity());
                27. //Getthelayoutinflater
                28. LayoutInflaterinflater=getActivity().getLayoutInflater();
                29. Viewview=inflater.inflate(R.layout.fragment_login_dialog,null);
                30. mUsername=(EditText)view.findViewById(R.id.id_txt_username);
                31. mPassword=(EditText)view.findViewById(R.id.id_txt_password);
                32. //Inflateandsetthelayoutforthedialog
                33. //Passnullastheparentviewbecauseitsgoinginthedialoglayout
                34. builder.setView(view)
                35. //Addactionbuttons
                36. .setPositiveButton("Signin",
                37. newDialogInterface.OnClickListener()
                38. {
                39. @Override
                40. publicvoidonClick(DialogInterfacedialog,intid)
                41. {
                42. LoginInputListenerlistener=(LoginInputListener)getActivity();
                43. listener.onLoginInputComplete(mUsername
                44. .getText().toString(),mPassword
                45. .getText().toString());
                46. }
                47. }).setNegativeButton("Cancel",null);
                48. returnbuilder.create();
                49. }
                50. }
                   

                  拿到username和password的引用,在点击登录的时候,把activity强转为我们自定义的接口:LoginInputListener,然后将用户输入的数据返回。

                   

                  MainActivity中需要实现我们的接口LoginInputListener,实现我们的方法,就可以实现当用户点击登陆时,获得我们的帐号密码了:

                   

                  [java]view plaincopy
                   
                   
                   
                  1. c)MainActivity
                  2. packagecom.example.zhy_dialogfragment;
                  3.  
                  4. importcom.example.zhy_dialogfragment.LoginDialogFragment.LoginInputListener;
                  5.  
                  6. importandroid.app.Activity;
                  7. importandroid.app.AlertDialog;
                  8. importandroid.content.DialogInterface;
                  9. importandroid.os.Bundle;
                  10. importandroid.view.LayoutInflater;
                  11. importandroid.view.View;
                  12. importandroid.widget.Toast;
                  13.  
                  14. publicclassMainActivityextendsActivityimplementsLoginInputListener
                  15. {
                  16.  
                  17. @Override
                  18. protectedvoidonCreate(BundlesavedInstanceState)
                  19. {
                  20. super.onCreate(savedInstanceState);
                  21. setContentView(R.layout.activity_main);
                  22. }
                  23.  
                  24.  
                  25.  
                  26. publicvoidshowLoginDialog(Viewview)
                  27. {
                  28. LoginDialogFragmentdialog=newLoginDialogFragment();
                  29. dialog.show(getFragmentManager(),"loginDialog");
                  30.  
                  31. }
                  32.  
                  33. @Override
                  34. publicvoidonLoginInputComplete(Stringusername,Stringpassword)
                  35. {
                  36. Toast.makeText(this,"帐号:"+username+",密码:"+password,
                  37. Toast.LENGTH_SHORT).show();
                  38. }
                  39.  
                  40. }
                     

                    效果:

                     

                    \

                    6、DialogFragment做屏幕适配

                    我们希望,一个对话框在大屏幕上以对话框的形式展示,而小屏幕上则直接嵌入当前的Actvity中。这种效果的对话框,只能通过重写onCreateView实现。下面我们利用上面的EditNameDialogFragment来显示。

                    EditNameDialogFragment我们已经编写好了,直接在MainActivity中写调用

                     

                    [java]view plaincopy
                     
                     
                     
                    1. publicvoidshowDialogInDifferentScreen(Viewview)
                    2. {
                    3. FragmentManagerfragmentManager=getFragmentManager();
                    4. EditNameDialogFragmentnewFragment=newEditNameDialogFragment();
                    5.  
                    6. booleanmIsLargeLayout=getResources().getBoolean(R.bool.large_layout);
                    7. Log.e("TAG",mIsLargeLayout+"");
                    8. if(mIsLargeLayout)
                    9. {
                    10. //Thedeviceisusingalargelayout,soshowthefragmentasa
                    11. //dialog
                    12. newFragment.show(fragmentManager,"dialog");
                    13. }else
                    14. {
                    15. //Thedeviceissmaller,soshowthefragmentfullscreen
                    16. FragmentTransactiontransaction=fragmentManager
                    17. .beginTransaction();
                    18. //Foralittlepolish,specifyatransitionanimation
                    19. transaction
                    20. .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
                    21. //Tomakeitfullscreen,usethe'content'rootviewasthe
                    22. //container
                    23. //forthefragment,whichisalwaystherootviewfortheactivity
                    24. transaction.replace(R.id.id_ly,newFragment)
                    25. .commit();
                    26. }
                    27. }
                       

                      可以看到,我们通过读取R.bool.large_layout,然后根据得到的布尔值,如果是大屏幕则直接以对话框显示,如果是小屏幕则嵌入我们的Activity布局中

                       

                      这个R.bool.large_layout是我们定义的资源文件:

                      在默认的values下新建一个bools.xml

                       

                      [html]view plaincopy
                       
                       
                       
                      1.  
                      2.  
                      3. false
                      4.  
                      5.  
                      6.  

                        然后在res下新建一个values-large,在values-large下再新建一个bools.xml

                         

                         

                        [html]view plaincopy
                         
                         
                         
                        1.  
                        2.  
                        3. true
                        4.  
                        5.  
                        6.  

                          最后测试:

                           

                          \ \

                          左边为模拟器,右边为我的手机~~~~~

                          7、屏幕旋转

                          当用户输入帐号密码时,忽然旋转了一下屏幕,帐号密码不见了~~~是不是会抓狂

                          传统的new AlertDialog在屏幕旋转时,第一不会保存用户输入的值,第二还会报异常,因为Activity销毁前不允许对话框未关闭。而通过DialogFragment实现的对话框则可以完全不必考虑旋转的问题。

                          我们直接把上面登录使用AlertDialog创建的登录框,拷贝到MainActivity中直接调用:

                           

                          [java]view plaincopy
                           
                           
                           
                          1. publicvoidshowLoginDialogWithoutFragment(Viewview)
                          2. {
                          3. AlertDialog.Builderbuilder=newAlertDialog.Builder(this);
                          4. //Getthelayoutinflater
                          5. LayoutInflaterinflater=this.getLayoutInflater();
                          6.  
                          7. //Inflateandsetthelayoutforthedialog
                          8. //Passnullastheparentviewbecauseitsgoinginthedialoglayout
                          9. builder.setView(inflater.inflate(R.layout.fragment_login_dialog,null))
                          10. //Addactionbuttons
                          11. .setPositiveButton("Signin",
                          12. newDialogInterface.OnClickListener()
                          13. {
                          14. @Override
                          15. publicvoidonClick(DialogInterfacedialog,intid)
                          16. {
                          17. //signintheuser...
                          18. }
                          19. }).setNegativeButton("Cancel",null).show();
                          20. }
                             

                            下面我分别点击两种方式创建的登录框,看效果图:

                             

                            \

                            可以看到,传统的Dialog旋转屏幕时就消失了,且后台log会报异常~~~使用DialogFragment则不受影响。

                             

                             

                            好了,关于DialogFragment的介绍结束~~~~

                             

                            有任何疑问请留言

                             

                            源码点击下载

                             

                            参考文档:

                            http://developer.android.com/guide/topics/ui/dialogs.html#DialogFragment

                            https://github.com/thecodepath/android_guides/wiki/Using-DialogFragment

                             

          用户评论