DialogFragment实现对话框
对话框在项目正很常见,以前做项目我基本上都是用AlertDialog实现对话框。DialogFragment出现以后,我就很少再用其他方式实现对话框交互了。几乎所有项目中的弹框都通过DialogFragment实现。
这篇文章从以下几个角度总结使用DialogFragment:
- 生命周期
- 基本对话框实现
- Alert Dialog实现
DialogFragment的生命周期
DialogFragment做了各种各样的事情来处理碎片的生命周期,DialogFragment需要保证碎片和Dialog显示过程中保持一致的状态,DialogFragment监视从对话框中删除事件,并负责在发生时删除它自己的状态。我们必须使用show方法来为UI添加一个对话片段的实例,当对话框被删除时,这些记录的对话框片段应该被删除。
DialogFragment有完整的生命周期处理,我们不需要关心如何控制其生命周期。
Basic Dialog
DialogFragment作为基本的Dialog使用,我们可以自由扩展其样式,布局。下面是一个DialogFragment的基本用法:
public class MyDialogFragment extends DialogFragment {
/**
* 定义一个标识
*/
private int mNum;
/**
* Create a new instance of MyDialogFragment, providing "num"
* as an argument.
*/
public static MyDialogFragment newInstance(int num) {
MyDialogFragment f = new MyDialogFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments().getInt("num");
// Pick a style based on the num.
int style = DialogFragment.STYLE_NORMAL, theme = 0;
switch ((mNum-1)%6) {
case 1:
style = DialogFragment.STYLE_NO_TITLE;
break;
case 2:
style = DialogFragment.STYLE_NO_FRAME;
break;
case 3:
style = DialogFragment.STYLE_NO_INPUT;
break;
case 4:
style = DialogFragment.STYLE_NORMAL;
break;
case 5:
style = DialogFragment.STYLE_NORMAL;
break;
case 6:
style = DialogFragment.STYLE_NO_TITLE;
break;
case 7:
style = DialogFragment.STYLE_NO_FRAME;
break;
case 8:
style = DialogFragment.STYLE_NORMAL;
break;
}
switch ((mNum-1)%6) {
case 4:
theme = android.R.style.Theme_Holo;
break;
case 5:
theme = Theme_Holo_Light_Dialog;
break;
case 6:
theme = Theme_Holo_Light;
break;
case 7:
theme = Theme_Holo_Light_Panel;
break;
case 8:
theme = Theme_Holo_Light;
break;
}
setStyle(style, theme);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_dialog, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText("Dialog #" + mNum + ": using style "
+ getNameForNum(mNum));
// Watch for button clicks.
Button button = (Button)v.findViewById(R.id.show);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// When button is clicked, call up to owning activity.
((MainActivity)getActivity()).showDialog();
}
});
return v;
}
private String getNameForNum(int mNum){
String result = "";
switch (mNum){
case 4:
result = "Theme_Holo";
break;
case 5:
result = "Theme_Holo_Light_Dialog";
break;
case 6:
result = "Theme_Holo_Light";
break;
case 7:
result = "Theme_Holo_Light_Panel";
break;
case 8:
result = "Theme_Holo_Light";
break;
}
return result;
}
}
代码很简单,包括Fragment的基本初始化方法,onCreate方法中控制对话框显示的样式,onCreateView中实例化对话框的布局。
Activity中使用:
...
private int mStackLevel = 0;
...
public void showDialog() {
mStackLevel++;
// DialogFragment.show() will take care of adding the fragment
// in a transaction. We also want to remove any currently showing
// dialog, so make our own transaction and take care of that here.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
newFragment.show(ft,"dialog");
}
同样通过Fragment的事务进行管理,使用show方法实现展示。
Alert Dialog
上面是通过实现onCreateView方法实现的View,Alert Dialog实现方式是通过实现 onCreateDialog来创建对话框。
public class MyAlertDialogFragment extends DialogFragment {
public static MyAlertDialogFragment newInstance(String title) {
MyAlertDialogFragment frag = new MyAlertDialogFragment();
Bundle args = new Bundle();
args.putString("title", title);
frag.setArguments(args);
return frag;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
String title = getArguments().getString("title");
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.alert_dialog_icon)
.setTitle(title)
.setMessage("这里是内容显示")
.setPositiveButton("确认",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((MainActivity)getActivity()).doPositiveClick();
}
}
)
.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((MainActivity)getActivity()).doNegativeClick();
}
}
)
.create();
}
}
Activity中的调用,这里Dialog中点击确认和取消都是调用的Activity中的方法:
void showAlertDialog() {
DialogFragment newFragment = MyAlertDialogFragment.newInstance(
"Alert 标题");
newFragment.show(getSupportFragmentManager(), "dialog");
}
public void doPositiveClick() {
// Do stuff here.
Log.i("FragmentAlertDialog", "Positive click!");
Toast.makeText(this ,"确认" ,Toast.LENGTH_SHORT).show();
}
public void doNegativeClick() {
// Do stuff here.
Log.i("FragmentAlertDialog", "Negative click!");
Toast.makeText(this ,"取消" ,Toast.LENGTH_SHORT).show();
}
此外DialogFragment同样可以作为Fragment在Activity中使用,灵活性非常高。
上面是FragmentDialog的基本用法以及核心知识点。下面代码是我在项目中具体的应用:
public class EditFloatValueDialog extends DialogFragment {
@BindView(R.id.tv_operat_name)TextView operatNameTV;
@BindView(R.id.et_value)EditText valueET;
private static String mTitle;
private static String mOldValue="";
private MyDialogListener listener;
public static EditFloatValueDialog newInstance(String title,String oldValue){
mTitle=title;
mOldValue=oldValue;
return new EditFloatValueDialog();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_TITLE,android.R.style.Theme_Material_Light_Dialog_MinWidth);
setCancelable(true);
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
dialog.getWindow().setLayout((int) (dm.widthPixels * 0.5), ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View dialogView=inflater.inflate(R.layout.dialog_edit_float,container,false);
ButterKnife.bind(this,dialogView);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
String mTitleStr = mTitle.replace(":","").replace(":","");
operatNameTV.setText(mTitleStr);
if(!TextUtils.isEmpty(mOldValue)){
valueET.setText(mOldValue);
valueET.setSelection(mOldValue.length());
}
return dialogView;
}
@OnClick(R.id.btn_save)
public void dialogClick(){
if(listener!=null){
String value=valueET.getText().toString();
if(TextUtils.isEmpty(value)){
T.showShort(getActivity(),R.string.edit_empty);
return;
}
dismiss();
listener.save(value);
}
}
public void setMyDialogListener(MyDialogListener listener){
this.listener=listener;
}
}
在onStart中可以随意控制对话框的大小,onCreate中改变对话框的样式,然后通过接口回调事件处理对话框中交互事件。上面实例也是FragmentDialog的最常用的使用方式。
建议大家都是用FragmentDialog来实现对话框显示。
如果有帮助,欢迎留言点赞,谢谢!