(4.1.24)Android(安卓)官方推荐 DialogFragment 创建对话框
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37815413
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 plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/id_label_your_name"
- android:layout_width="wrap_content"
- android:layout_height="32dp"
- android:gravity="center_vertical"
- android:text="Yourname:"/>
- <EditText
- android:id="@+id/id_txt_your_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/id_label_your_name"
- android:imeOptions="actionDone"
- android:inputType="text"/>
- <Button
- android:id="@+id/id_sure_edit_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/id_txt_your_name"
- android:text="ok"/>
- </RelativeLayout>
b)继承DialogFragment,重写onCreateView方法
[java] view plain copy
- packagecom.example.zhy_dialogfragment;
- importandroid.app.DialogFragment;
- importandroid.os.Bundle;
- importandroid.view.LayoutInflater;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- publicclassEditNameDialogFragmentextendsDialogFragment
- {
- @Override
- publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
- BundlesavedInstanceState)
- {
- Viewview=inflater.inflate(R.layout.fragment_edit_name,container);
- returnview;
- }
- }
c)测试运行:
Main方法中调用:
[java] view plain copy
- publicvoidshowEditDialog(Viewview)
- {
- EditNameDialogFragmenteditNameDialog=newEditNameDialogFragment();
- editNameDialog.show(getFragmentManager(),"EditNameDialog");
- }
可以看到,对话框成功创建并显示出来,不过默认对话框有个讨厌的标题,我们怎么去掉呢:可以在onCreateView中调用getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);即可去掉。即: [java] view plain copy
- publicclassEditNameDialogFragmentextendsDialogFragment
- {
- @Override
- publicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,
- BundlesavedInstanceState)
- {
- getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
- Viewview=inflater.inflate(R.layout.fragment_edit_name,container);
- returnview;
- }
- }
效果图:
很完美的去掉了讨厌的标题。
4、 重写onCreateDialog创建Dialog
在onCreateDialog中一般可以使用AlertDialog或者Dialog创建对话框,不过既然google不推荐直接使用Dialog,我们就使用AlertDialog来创建一个登录的对话框。
a)布局文件
[html] view plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="64dp"
- android:background="#FFFFBB33"
- android:contentDescription="@string/app_name"
- android:scaleType="center"
- android:src="@drawable/title"/>
- <EditText
- android:id="@+id/id_txt_username"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
- android:layout_marginTop="16dp"
- android:hint="inputusername"
- android:inputType="textEmailAddress"/>
- <EditText
- android:id="@+id/id_txt_password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
- android:layout_marginTop="4dp"
- android:fontFamily="sans-serif"
- android:hint="inputpassword"
- android:inputType="textPassword"/>
- </LinearLayout>
b)继承DialogFragment重写onCreateDialog方法
[java] view plain copy
- packagecom.example.zhy_dialogfragment;
- importandroid.app.AlertDialog;
- importandroid.app.Dialog;
- importandroid.app.DialogFragment;
- importandroid.content.DialogInterface;
- importandroid.os.Bundle;
- importandroid.view.LayoutInflater;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.widget.EditText;
- publicclassLoginDialogFragmentextendsDialogFragment
- {
- @Override
- publicDialogonCreateDialog(BundlesavedInstanceState)
- {
- AlertDialog.Builderbuilder=newAlertDialog.Builder(getActivity());
- //Getthelayoutinflater
- LayoutInflaterinflater=getActivity().getLayoutInflater();
- Viewview=inflater.inflate(R.layout.fragment_login_dialog,null);
- //Inflateandsetthelayoutforthedialog
- //Passnullastheparentviewbecauseitsgoinginthedialoglayout
- builder.setView(view)
- //Addactionbuttons
- .setPositiveButton("Signin",
- newDialogInterface.OnClickListener()
- {
- @Override
- publicvoidonClick(DialogInterfacedialog,intid)
- {
- }
- }).setNegativeButton("Cancel",null);
- returnbuilder.create();
- }
- }
c)调用
[java] view plain copy
- publicvoidshowLoginDialog(Viewview)
- {
- LoginDialogFragmentdialog=newLoginDialogFragment();
- dialog.show(getFragmentManager(),"loginDialog");
- }
效果图:
可以看到通过重写onCreateDialog同样可以实现创建对话框,效果还是很nice的。
5、传递数据给Activity
从dialog传递数据给Activity,可以使用“fragment interface pattern”的方式,下面通过一个改造上面的登录框来展示这种模式。
改动比较小,直接贴代码了:
[java] view plain copy
- packagecom.example.zhy_dialogfragment;
- importandroid.app.AlertDialog;
- importandroid.app.Dialog;
- importandroid.app.DialogFragment;
- importandroid.content.DialogInterface;
- importandroid.os.Bundle;
- importandroid.view.LayoutInflater;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.widget.EditText;
- publicclassLoginDialogFragmentextendsDialogFragment
- {
- privateEditTextmUsername;
- privateEditTextmPassword;
- publicinterfaceLoginInputListener
- {
- voidonLoginInputComplete(Stringusername,Stringpassword);
- }
- @Override
- publicDialogonCreateDialog(BundlesavedInstanceState)
- {
- AlertDialog.Builderbuilder=newAlertDialog.Builder(getActivity());
- //Getthelayoutinflater
- LayoutInflaterinflater=getActivity().getLayoutInflater();
- Viewview=inflater.inflate(R.layout.fragment_login_dialog,null);
- mUsername=(EditText)view.findViewById(R.id.id_txt_username);
- mPassword=(EditText)view.findViewById(R.id.id_txt_password);
- //Inflateandsetthelayoutforthedialog
- //Passnullastheparentviewbecauseitsgoinginthedialoglayout
- builder.setView(view)
- //Addactionbuttons
- .setPositiveButton("Signin",
- newDialogInterface.OnClickListener()
- {
- @Override
- publicvoidonClick(DialogInterfacedialog,intid)
- {
- LoginInputListenerlistener=(LoginInputListener)getActivity();
- listener.onLoginInputComplete(mUsername
- .getText().toString(),mPassword
- .getText().toString());
- }
- }).setNegativeButton("Cancel",null);
- returnbuilder.create();
- }
- }
拿到username和password的引用,在点击登录的时候,把activity强转为我们自定义的接口:LoginInputListener,然后将用户输入的数据返回。
MainActivity中需要实现我们的接口LoginInputListener,实现我们的方法,就可以实现当用户点击登陆时,获得我们的帐号密码了:
[java] view plain copy
- c)MainActivity
- packagecom.example.zhy_dialogfragment;
- importcom.example.zhy_dialogfragment.LoginDialogFragment.LoginInputListener;
- importandroid.app.Activity;
- importandroid.app.AlertDialog;
- importandroid.content.DialogInterface;
- importandroid.os.Bundle;
- importandroid.view.LayoutInflater;
- importandroid.view.View;
- importandroid.widget.Toast;
- publicclassMainActivityextendsActivityimplementsLoginInputListener
- {
- @Override
- protectedvoidonCreate(BundlesavedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- publicvoidshowLoginDialog(Viewview)
- {
- LoginDialogFragmentdialog=newLoginDialogFragment();
- dialog.show(getFragmentManager(),"loginDialog");
- }
- @Override
- publicvoidonLoginInputComplete(Stringusername,Stringpassword)
- {
- Toast.makeText(this,"帐号:"+username+",密码:"+password,
- Toast.LENGTH_SHORT).show();
- }
- }
效果:
6、DialogFragment做屏幕适配
我们希望,一个对话框在大屏幕上以对话框的形式展示,而小屏幕上则直接嵌入当前的Actvity中。这种效果的对话框,只能通过重写onCreateView实现。下面我们利用上面的EditNameDialogFragment来显示。
EditNameDialogFragment我们已经编写好了,直接在MainActivity中写调用
[java] view plain copy
- publicvoidshowDialogInDifferentScreen(Viewview)
- {
- FragmentManagerfragmentManager=getFragmentManager();
- EditNameDialogFragmentnewFragment=newEditNameDialogFragment();
- booleanmIsLargeLayout=getResources().getBoolean(R.bool.large_layout);
- Log.e("TAG",mIsLargeLayout+"");
- if(mIsLargeLayout)
- {
- //Thedeviceisusingalargelayout,soshowthefragmentasa
- //dialog
- newFragment.show(fragmentManager,"dialog");
- }else
- {
- //Thedeviceissmaller,soshowthefragmentfullscreen
- FragmentTransactiontransaction=fragmentManager
- .beginTransaction();
- //Foralittlepolish,specifyatransitionanimation
- transaction
- .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
- //Tomakeitfullscreen,usethe'content'rootviewasthe
- //container
- //forthefragment,whichisalwaystherootviewfortheactivity
- transaction.replace(R.id.id_ly,newFragment)
- .commit();
- }
- }
可以看到,我们通过读取R.bool.large_layout,然后根据得到的布尔值,如果是大屏幕则直接以对话框显示,如果是小屏幕则嵌入我们的Activity布局中
这个R.bool.large_layout是我们定义的资源文件:
在默认的values下新建一个bools.xml
[html] view plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <boolname="large_layout">false</bool>
- </resources>
然后在res下新建一个values-large,在values-large下再新建一个bools.xml
[html] view plain copy
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <boolname="large_layout">true</bool>
- </resources>
最后测试:
左边为模拟器,右边为我的手机~~~~~
7、屏幕旋转
当用户输入帐号密码时,忽然旋转了一下屏幕,帐号密码不见了~~~是不是会抓狂
传统的new AlertDialog在屏幕旋转时,第一不会保存用户输入的值,第二还会报异常,因为Activity销毁前不允许对话框未关闭。而通过DialogFragment实现的对话框则可以完全不必考虑旋转的问题。
我们直接把上面登录使用AlertDialog创建的登录框,拷贝到MainActivity中直接调用:
[java] view plain copy
- publicvoidshowLoginDialogWithoutFragment(Viewview)
- {
- AlertDialog.Builderbuilder=newAlertDialog.Builder(this);
- //Getthelayoutinflater
- LayoutInflaterinflater=this.getLayoutInflater();
- //Inflateandsetthelayoutforthedialog
- //Passnullastheparentviewbecauseitsgoinginthedialoglayout
- builder.setView(inflater.inflate(R.layout.fragment_login_dialog,null))
- //Addactionbuttons
- .setPositiveButton("Signin",
- newDialogInterface.OnClickListener()
- {
- @Override
- publicvoidonClick(DialogInterfacedialog,intid)
- {
- //signintheuser...
- }
- }).setNegativeButton("Cancel",null).show();
- }
下面我分别点击两种方式创建的登录框,看效果图:
可以看到,传统的Dialog旋转屏幕时就消失了,且后台log会报异常~~~使用DialogFragment则不受影响。
好了,关于DialogFragment的介绍结束~~~~
有任何疑问请留言
源码点击下载
参考文档:
http://developer.android.com/guide/topics/ui/dialogs.html#DialogFragment
https://github.com/thecodepath/android_guides/wiki/Using-DialogFragment
更多相关文章
- 第一时间测试TensorflowLite Android(安卓)Demo,性能平均200ms
- Android(安卓)开机视频
- android 读取文件相关
- Android(安卓)Studio创建RelativeLayout和LinearLayout布局layou
- Android中DialogFragment的简单使用及常见问题
- Android(安卓)Architecture(安卓架构)的一些研究
- Android(安卓)avd 在电脑上创建sdcard
- Android(安卓)Studio AIDL创建案例(解决自动生成java问题)
- android 简单试题系统