DialogFragment封装

android的弹框大概有:PopupWindow,Dialog,DialogFragment

Android官方推荐使用DialogFragment来代替传统的Dialog ,可以让它具有更高的可复用性(降低耦合)和更好的便利性,
主要是继承Fragment的优点和缺点:
优点:fragment的生命周期管理和碎片化
缺点:fragment的一些坑,参考传送门

PopupWindow更合适相对控件位置弹出,更容易设置指定显示的位置,网上说:
Dialog是非阻塞式对话框,而PopupWindow是阻塞式对话框
这里我使用时候发现,就算PopupWindow弹出来了,后续toast和dialog还能弹出来,当前页面的其他控件也能响应
PopupWindow能不能屏蔽屏幕的点击事件,主要是如下设置:

1
2
3
4
// 设置popupWindow获得焦点  
popupWindow.setTouchable(true);
// 设置popupWindow以外的区域可点击,点击后空白处,对话框消失
popupWindow.setOutsideTouchable(true);

关于PopupWindow,会另开一篇,接下来写一些简单的DialogFragment封装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class BaseDialogFragment extends DialogFragment {

private String mDialogName;

/**
* 监听弹出窗是否被取消
*/
private OnDialogCancelListener mCancelListener;
/**
* 回调获得需要显示的dialog
*/
private OnCallDialog mOnCallDialog;

public interface OnDialogCancelListener {
void onCancel();
}

public interface OnCallDialog {
Dialog getDialog(Context context);
}

public static BaseDialogFragment newInstance(OnCallDialog dialog, boolean cancelable,String dialogName)
{
return newInstance(dialog, cancelable,dialogName, null);
}


public static BaseDialogFragment newInstance(OnCallDialog dialog, boolean cancelable,String dialogName, OnDialogCancelListener cancelListener)
{
BaseDialogFragment instance = new BaseDialogFragment();
instance.setCancelable(cancelable);
instance.mCancelListener = cancelListener;
instance.mOnCallDialog = dialog;
instance.mDialogName = dialogName;
return instance;
}

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
if (null == mOnCallDialog) {
super.onCreateDialog(savedInstanceState);
}
return mOnCallDialog.getDialog(getActivity());
}

/**
*
* @param activity
*/
public void show(FragmentActivity activity)
{
Fragment prev = activity.getSupportFragmentManager().findFragmentByTag(mDialogName);
if (prev == null) {
FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
ft.add(this, mDialogName);
ft.commitAllowingStateLoss();
// show(activity.getSupportFragmentManager(), mDialogName);
}
}

@Override
public void onCancel(DialogInterface dialog)
{
super.onCancel(dialog);
if (mCancelListener != null) {
mCancelListener.onCancel();
}
}
}

这里通过dialogName来标识dialog的唯一性,避免创建多种相同的dialog。
使用commitAllowingStateLoss()方法提交,避免产生异常:Can not perform this action after onSaveInstanceState
但是这样也放弃了fragment状态的恢复。该异常产生的原因:在你离开当前Activity等情况下,
系统会调用onSaveInstanceState()帮你保存当前Activity的状态、数据等,
直到再回到该Activity之前(onResume()之前),你执行Fragment事务,
就会抛出该异常!(一般是其他Activity的回调让当前页面执行事务的情况,会引发该问题)

具体的Dialog:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class LoadingDialog extends Dialog {

public static void showDialog(FragmentActivity activity,boolean cancelable)
{
BaseDialogFragment fragment = BaseDialogFragment.newInstance(new BaseDialogFragment.OnCallDialog() {
@Override
public Dialog getDialog(Context context)
{
return new LoadingDialog(context);
}
},cancelable,LoadingDialog.class.getName());
fragment.show(activity);
}

public static void disDialog(FragmentActivity activity)
{
if(activity != null)
{
Fragment prev = activity.getSupportFragmentManager()
.findFragmentByTag(LoadingDialog.class.getName());
if (prev != null) {
((DialogFragment) prev).dismissAllowingStateLoss();
}
}
}

private Context mContext;
private AnimationDrawable animationDrawable;
public LoadingDialog(@NonNull Context context)
{
this(context, R.style.loadding_dialog);
}

public LoadingDialog(@NonNull Context context, @StyleRes int themeResId)
{
super(context, themeResId);
mContext = context;
}

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ImageView imageView = new ImageView(mContext);
imageView.setBackgroundResource(R.drawable.bg_loading);
imageView.setImageResource(R.drawable.loading);
int padding = DeviceUtil.dip2px(mContext,10);
int width = DeviceUtil.dip2px(mContext,120);
imageView.setPadding(padding,padding,padding,padding);
animationDrawable = (AnimationDrawable) imageView.getDrawable();
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(width
,width);
setContentView(imageView,layoutParams);
animationDrawable.start();

setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog)
{
if(animationDrawable != null)
{
animationDrawable.stop();
}
}
});
}
}

可以看到dialog和DialogFragment是很分离的,感觉像是套了一层,dialog也可以直接使用。

坚持原创分享,您的支持将鼓励我继续创作!