#.简介
DialogFragment是继承Fragment,兼具Fragment和Dialog的特点:
一方面,它具有Fragment的生命周期,可以由Activity的FragmentManager来管理器生命周期;
另一方面,其内部包含一个Dialog成员变量,可以像窗口一样展示。
##.DialogFragment相对于Dialog的优点:
Dialog的生命周期不会随着Activity生命周期变化而变化,而DialogFragment继承自Fragment,具有与Fragment相同的生命周期和管理方式,FragmentManager会自动管理DialogFragment的生命周期。
所以在特定场景下,DialogFragment的生命周期管理起来更方便,例如:旋转屏幕等配置变化导致Activity重新创建时,Dialog会消失不见,而DialogFragment会由FragmentManager自动重建。
谷歌官方推荐使用DialogFragment来代替Dialog。
##使用要点和示例
分析源代码可知,DialogFragment内部包含一个Dialog实例,显示的窗口实际上是这个Dialog实例的窗口。
1. 这个Dialog实例通过onCreateDialog()方法创建,可以覆写该方法,返回自定义的Dialog,如果界面简单的话,其实只覆写该方法就可以实现传统Dialog需要实现的业务。
2. 如果界面复杂的话,则需要在onCreateView()方法中返回需要显示的View,就像普通Fragment中一样。所不同的无非是,在onActivityCreated()中,DialogFragment内部会获取前面返回的View,如果返回的View不是null的话,则会调用mDialog.setContentView(view),将该View设置为Dialog的显示内容。
也就是说,onCreateDialog()和onCreateView()实际上重写一个就行了,两个都重写是无意义的。如果在onCreateView()中自定了界面,它会覆盖内部Dialog的界面。如果前面在onCreateDialog()中自定义了Dialog的界面,这个界面也会被后面的覆盖掉。
3. 窗口大小的代码逻辑,放在子类的onActivityCreated()、或onStart()、onResume()方法中才会生效。个人习惯放在onActivityCreated()中。
至于设置窗口大小的方法,与Dialog中类似,都是针对调用Window的api进行设置。
原因:参考剪藏DialogFragment源码分析 - 简书中的2.4节,如果用onCreateView()来自定义界面,直到onCreateActivity()时,DialogFragment的窗体才被创建出来,因此设置窗口大小的代码逻辑,不能放在更早的生命周期,而是应放在onActivityCreated()、或onStart()、onResume()方法中。
4.通过setStyle()方法设置样式,示例和说明如下:
setStyle(DialogFragment.STYLE_NO_TITLE, 【自定义的样式,例如R.style.CenterDialog】);
参数1的有以下值可选:
STYLE_NORMAL:会显示一个普通的dialog
STYLE_NO_TITLE:不带标题的dialog
STYLE_NO_FRAME:无框的dialog
STYLE_NO_INPUT:无法输入内容的dialog,即不接收输入的焦点,而且触摸无效。
通过setStyle()设置样式,要在onCreateView之前才有效。一般来讲,都会放到onCreate中调用。
原因参考剪藏DialogFragment源码分析 - 简书2.2节。
5.显示和隐藏弹窗的方法
5.1显示
最简便常用的显示方法:
RecDialogFragment dialogFragment = RecDialogFragment.newInstance("一个参数”);
//show()方法的第二个参数是tag,DialogFragment也是一个Fragment,在FragmentManager中会把该DialogFragment与传入的tag绑定在一起,便于后继管理。如果用不到tag,也可以传入空值“”。
dialogFragment.show(getSupportFragmentManager(), "dialogFragment");
参考剪藏DialogFragment源码分析 - 简书2.6节。
5.2隐藏
使用dismiss() 或 dismissAllowingStateLoss()。
二者的区别参考剪藏DialogFragment源码分析 - 简书2.6节。
用前者时有时会出错,故推荐用dismissAllowingStateLoss(),原因参考:DialogFragment 崩溃异常 IllegalStateException:Can not perform this action after onSaveInstanceState - 简书
(!!!!区别和原因都还没仔细看,有空去看一看,分析一下!!!)
6.在初始化DialogFragment需要传值时,可以像普通Fragment一样通过setArgruments(Bundle)传入值,然后在任意生命周期通过getArgruments()取出值使用。
对于Fragment,惯有的写法是通常会写一个静态的构建实例的函数,参数为外部需要传入的值:
public static RecDialogFragment newInstance(String name){
RecDialogFragment dialogFragment = new RecDialogFragment();
Bundle bundle = new Bundle();
bundle.putString("name", name);
dialogFragment.setArguments(bundle);
return dialogFragment;
}
取用的示例代码:
Bundle bundle = getArguments();
String name = bundle.getString("name");
7.DialogFragment单个实例只能show()一次,再次show()会抛出异常。
参考剪藏:DialogFragment细枝末节 - 简书
8.可覆写onDissmiss()方法,对DialogFragment的隐藏进行监听。
9.示例代码
public class RecDialogFragment extends DialogFragment {
public static RecDialogFragment newInstance(String name){
RecDialogFragment dialogFragment = new RecDialogFragment();
Bundle bundle = new Bundle();
bundle.putString("name", name);
dialogFragment.setArguments(bundle);
return dialogFragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置窗口样式
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.RecCommonDialog);
}
private TextView mTvName;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//设置界面
View view = inflater.inflate(R.layout.dialogfragment_rec, null);
mTvName = (TextView)view.findViewById(R.id.tv_name);
view.findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//隐藏窗口
// dismiss();
dismissAllowingStateLoss();
}
});
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//设置窗口显示位置、大小
Dialog dialog = getDialog();
if(dialog != null){
Window window = dialog.getWindow();
window.setGravity(Gravity.CENTER);
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = (int)(dm.widthPixels*0.7);
lp.height = (int)(dm.heightPixels*0.6);
window.setAttributes(lp);
}
}
@Override
public void onStart() {
super.onStart();
Bundle bundle = getArguments();
String name = bundle.getString("name");
mTvName.setText(name);
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onDetach() {
super.onDetach();
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
}
}
参考剪藏:
DialogFragment源码分析 - 简书
DialogFragment细枝末节 - 简书