1. DialogHelper
这不是一个自定义的Dialog
,而是一个Helper
,一开始想这个Helper
的目的侧重于配置组装Dialog
,而尽量少的改变Dialog
属性
项目中一共有10几个不同布局的Dialog
,里面输入、点击、选择不同的事件都有,想要使用一个Dialog
来满足所有的需求比较麻烦,一开始考虑的是写一个BaseDialog
,之后根据各个Dialog
来继承实现,然而还要写不同事件的接口回调,觉得继承BaseDialg
也比较麻烦,想着写一个简单能满足基础需求类似Utils
的东西
一开始考虑使用Builder
的方式比较好
网上搜索时,看到利用建造者模式封装一个简单好用的dialog,但这个虽然标题写的叫建造者
,但代码用的是单例
,个人感觉使用单例
不怎么合适,借鉴思路自己整理出来一个
希望各位同学能给出一些更好的思路
public final class DialogHelper {
private final Builder mBuilder;
private HummerDialogFragment mDialogFragment;
/** Fragment Tag */
private final String mTag;
private DialogHelper(Builder builder) {
this.mBuilder = builder;
this.mTag = builder.tag;
}
public void show(@NonNull LifecycleOwner owner, @NonNull FragmentManager manager) {
Lifecycle.State currentState = owner.getLifecycle().getCurrentState();
if (currentState == Lifecycle.State.DESTROYED) {
Log.d("DialogHelper", "--> owner State is DESTROYED");
return;
}
if (mDialogFragment == null) {
mDialogFragment = HummerDialogFragment.newInstance(mBuilder);
}
mDialogFragment.show(manager, mTag);
}
public void dismiss() {
if (mDialogFragment != null && mDialogFragment.getDialog().isShowing()) {
mDialogFragment.dismiss();
}
}
public static Builder myBuilder() {
return new Builder();
}
public static class Builder implements Parcelable {
/** 布局 ID */
private int mLayoutId;
/** 弹窗 Gravity 值 : 默认为 CENTER */
private int mGravity = Gravity.CENTER;
/** padding 值 : Left,Right 默认 15 dp */
private int mPaddingTop;
private int mPaddingBottom;
private int mPaddingRight = 15;
private int mPaddingLeft = 15;
/** 是否可以取消 */
private boolean mCancelable = true;
/** 点击外部是否可以消失 */
private boolean mOutCancelable = true;
/** 改变 View 内容 */
private List mViewIdList;
private SparseArray mArrayContentCallback;
/** 点击事件 */
private List mClickViewIdList;
private SparseArray mArrayPositiveClickListener;
/** 点击事件是否需要自动消失 : 默认 true */
private boolean mAutoDismissAble = true;
/** Fragment Tag */
private String tag = Builder.class.getSimpleName();
/** 背景透明度 */
private float alpha = 0.5F;
/** Dialog 的 height : WRAP_CONTENT or MATCH_PARENT */
private int layoutParams = WindowManager.LayoutParams.WRAP_CONTENT;
private Builder() {
}
/** 布局 ID */
public Builder layoutResId(@LayoutRes int layoutId) {
this.mLayoutId = layoutId;
return this;
}
int getLayoutId() {
return mLayoutId;
}
/** 位置 */
public Builder gravity(int gravity) {
this.mGravity = gravity;
return this;
}
public int getGravity() {
return mGravity;
}
/** 内边距 */
public Builder padding(int padding) {
left(padding);
top(padding);
right(padding);
bottom(padding);
return this;
}
/** Top , Bottom 内边距 */
public Builder topAndBottom(int padding) {
this.mPaddingTop = padding;
this.mPaddingBottom = padding;
return this;
}
/** Top , Bottom 内边距 */
public Builder leftAndRight(int padding) {
this.mPaddingTop = padding;
this.mPaddingBottom = padding;
return this;
}
/** Top 内边距 */
Builder top(int paddingTop) {
this.mPaddingTop = paddingTop;
return this;
}
int getTop() {
return mPaddingTop;
}
/** Left 内边距 */
public Builder left(int paddingLeft) {
this.mPaddingLeft = paddingLeft;
return this;
}
public int left() {
return mPaddingLeft;
}
int getBottom() {
return mPaddingBottom;
}
/** Bottom 内边距 */
public Builder bottom(int paddingBottom) {
this.mPaddingBottom = paddingBottom;
return this;
}
public int getRight() {
return mPaddingRight;
}
/** Right 内边距 */
public Builder right(int paddingRight) {
this.mPaddingRight = paddingRight;
return this;
}
/** 设置 back 键是否可以取消 */
public Builder cancelable(boolean cancelable) {
this.mCancelable = cancelable;
return this;
}
boolean isCancelable() {
return mCancelable;
}
/** 点击外部是否可以取消 */
public Builder outCancelable(boolean outCancelable) {
this.mOutCancelable = outCancelable;
return this;
}
boolean isOutCancelable() {
return mOutCancelable;
}
/** 根据 id,设置控件内容 */
public Builder widget(@IdRes int id,
@NonNull OnSetViewContentCallback onSetViewContentCallback) {
if (mViewIdList == null) {
mViewIdList = new ArrayList<>();
}
// 防止重复添加
if (mViewIdList.contains(id)) {
return this;
}
mViewIdList.add(id);
if (mArrayContentCallback == null) {
mArrayContentCallback = new SparseArray<>();
}
this.mArrayContentCallback.put(id, onSetViewContentCallback);
return this;
}
SparseArray getArrayContentCallback() {
return mArrayContentCallback;
}
/** 点击取消事件 */
public Builder onCancelClick(@IdRes int id) {
if (mClickViewIdList == null) {
mClickViewIdList = new ArrayList<>();
}
// 过滤
if (mClickViewIdList.contains(id)) {
return this;
}
mClickViewIdList.add(id);
return this;
}
List getClickViewIdList() {
return mClickViewIdList;
}
/** 点击事件 */
public Builder onPositiveClick(@IdRes int id,
@NonNull OnViewClickListener onViewClickListener) {
if (mClickViewIdList == null) {
mClickViewIdList = new ArrayList<>();
}
// 防止重复添加
if (mClickViewIdList.contains(id)) {
return this;
}
mClickViewIdList.add(id);
if (mArrayPositiveClickListener == null) {
mArrayPositiveClickListener = new SparseArray<>();
}
this.mArrayPositiveClickListener.put(id, onViewClickListener);
return this;
}
List getViewIdList() {
return mViewIdList;
}
SparseArray getArrayPositiveClickListener() {
return mArrayPositiveClickListener;
}
/** 点击时,是否自动关闭 */
public Builder autoDismissOnClick(boolean auto) {
this.mAutoDismissAble = auto;
return this;
}
boolean isAutoDismissAble() {
return mAutoDismissAble;
}
public String getTag() {
return tag;
}
public Builder tag(String tag) {
this.tag = tag;
return this;
}
/** 背景透明度 */
public Builder alpha(float alpha) {
this.alpha = alpha;
return this;
}
public float getAlpha() {
return alpha;
}
public int getHeightLayoutParams() {
return layoutParams;
}
/** 背景高度 */
public Builder heightLayoutParams(int layoutParams) {
this.layoutParams = layoutParams;
return this;
}
public DialogHelper build() {
return new DialogHelper(this);
}
@Override
public int describeContents() {
return 0;
}
@SuppressWarnings("unchecked")
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.mLayoutId);
dest.writeInt(this.mGravity);
dest.writeInt(this.mPaddingTop);
dest.writeInt(this.mPaddingBottom);
dest.writeInt(this.mPaddingRight);
dest.writeInt(this.mPaddingLeft);
dest.writeByte(this.mCancelable ? (byte) 1 : (byte) 0);
dest.writeByte(this.mOutCancelable ? (byte) 1 : (byte) 0);
dest.writeList(this.mViewIdList);
dest.writeSparseArray((SparseArray) this.mArrayContentCallback);
dest.writeList(this.mClickViewIdList);
dest.writeSparseArray((SparseArray) this.mArrayPositiveClickListener);
dest.writeByte(this.mAutoDismissAble ? (byte) 1 : (byte) 0);
dest.writeString(this.tag);
dest.writeFloat(this.alpha);
dest.writeInt(this.layoutParams);
}
@SuppressWarnings("unchecked")
protected Builder(Parcel in) {
this.mLayoutId = in.readInt();
this.mGravity = in.readInt();
this.mPaddingTop = in.readInt();
this.mPaddingBottom = in.readInt();
this.mPaddingRight = in.readInt();
this.mPaddingLeft = in.readInt();
this.mCancelable = in.readByte() != 0;
this.mOutCancelable = in.readByte() != 0;
this.mViewIdList = new ArrayList();
in.readList(this.mViewIdList, Integer.class.getClassLoader());
this.mArrayContentCallback =
in.readSparseArray(OnSetViewContentCallback.class.getClassLoader());
this.mClickViewIdList = new ArrayList();
in.readList(this.mClickViewIdList, Integer.class.getClassLoader());
this.mArrayPositiveClickListener =
in.readSparseArray(OnViewClickListener.class.getClassLoader());
this.mAutoDismissAble = in.readByte() != 0;
this.tag = in.readString();
this.alpha = in.readFloat();
this.layoutParams = in.readInt();
}
public static final Parcelable.Creator
CREATOR = new Parcelable.Creator() {
@Override
public Builder createFromParcel(Parcel source) {
return new Builder(source);
}
@Override
public Builder[] newArray(int size) {
return new Builder[size];
}
};
}
/** 改变 View 内容 */
public interface OnSetViewContentCallback {
/**
* View 内容
*
* @param v widget
*/
void setViewContent(T v);
}
/** 点击监听 : dialog 用来获取内部控件用,findViewById() */
public interface OnViewClickListener {
/**
* View 点击
*
* @param dialog 弹窗
*/
void setPositiveClick(Dialog dialog);
}
}
HummerDialogFragment
public class HummerDialogFragment extends DialogFragment {
private static final String BUNDLE_KEY = "Builder";
@LayoutRes
private int mLayoutId;
private int mGravity;
private int mPaddingTop;
private int mPaddingBottom;
private int mPaddingRight;
private int mPaddingLeft;
private boolean mCancelable;
private boolean mOutCancelable;
private float mAlpha;
private Context mContext;
private SparseArray mViewSparseArray;
private List mViewIdList;
private SparseArray mArrayContentCallback;
private List mClickViewIdList;
private SparseArray mArrayPositiveClickListener;
private boolean mAutoDismissAble;
private int mHeightLayoutParams = WindowManager.LayoutParams.WRAP_CONTENT;
public static HummerDialogFragment newInstance(@NonNull DialogHelper.Builder builder) {
Bundle args = new Bundle();
HummerDialogFragment fragment = new HummerDialogFragment();
args.putParcelable(BUNDLE_KEY, builder);
fragment.setArguments(args);
return fragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.mContext = context;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置样式
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.HummerDialogStyle);
init();
}
private void init() {
Bundle arguments = getArguments();
if (arguments == null) {
return;
}
DialogHelper.Builder builder = arguments.getParcelable(BUNDLE_KEY);
if (builder == null) {
return;
}
mLayoutId = builder.getLayoutId();
mGravity = builder.getGravity();
mPaddingTop = builder.getTop();
mPaddingLeft = builder.left();
mPaddingBottom = builder.getBottom();
mPaddingRight = builder.getRight();
mCancelable = builder.isCancelable();
mOutCancelable = builder.isOutCancelable();
mViewIdList = builder.getViewIdList();
mArrayContentCallback = builder.getArrayContentCallback();
mClickViewIdList = builder.getClickViewIdList();
mArrayPositiveClickListener = builder.getArrayPositiveClickListener();
mAutoDismissAble = builder.isAutoDismissAble();
mAlpha = builder.getAlpha();
mHeightLayoutParams = builder.getHeightLayoutParams();
}
/** 为了兼容性更好,在 onActivityCreated() 进行设置 setContentView() */
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Dialog dialog = getDialog();
// 点击消失
dialog.setCancelable(mCancelable);
dialog.setCanceledOnTouchOutside(mOutCancelable);
// 直接使用 layoutId 填充
dialog.setContentView(mLayoutId);
// window
initWindow(dialog);
// 监听
initSetContentCallback(dialog);
initClickListener(dialog);
}
@Override
public void onDestroyView() {
super.onDestroyView();
clean();
}
/** Window 配置 */
private void initWindow(Dialog dialog) {
final Window window = dialog.getWindow();
if (window == null) {
return;
}
// 背景透明度 0 - 1F
window.setDimAmount(mAlpha);
window.setGravity(mGravity);
window.getDecorView().setPadding(dp2Pix(mPaddingLeft)
, dp2Pix(mPaddingTop), dp2Pix(mPaddingRight), dp2Pix(mPaddingBottom));
// mHeightLayoutParams,根据布局确定。默认使用 WRAP_CONTENT
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, mHeightLayoutParams);
}
/** 点击监听 */
private void initClickListener(Dialog dialog) {
if (mClickViewIdList == null) {
return;
}
for (int id : mClickViewIdList) {
View view = getViewById(dialog, id);
if (view == null) {
throw new NullPointerException("点击回调, 内部 View 没有找到");
}
view.setOnClickListener(v -> {
// 是否自动 dismiss
boolean isAutoDis = mAutoDismissAble || (mArrayPositiveClickListener == null) ||
(mArrayPositiveClickListener.get(id) == null);
if (isAutoDis) {
// 当 mArrayPositiveClickListener == null
// mArrayPositiveClickListener.get(id) 为 null,说明当前 id 为点击取消事件
dismiss();
}
if (mArrayPositiveClickListener != null
&& mArrayPositiveClickListener.get(id) != null) {
mArrayPositiveClickListener.get(id).setPositiveClick(dialog);
}
});
}
}
/** 设置View 内容 */
@SuppressWarnings("unchecked")
private void initSetContentCallback(Dialog dialog) {
if (mViewIdList == null || mArrayContentCallback == null) {
return;
}
for (int id : mViewIdList) {
View view = getViewById(dialog, id);
if (view == null) {
throw new NullPointerException("设置 View 内容, 内部 View 没有找到");
}
mArrayContentCallback.get(id).setViewContent(view);
}
}
/**
* 根据 id 获取 widget
*
* @param id id
* @return widget
*/
private View getViewById(Dialog dialog, int id) {
if (mViewSparseArray == null) {
mViewSparseArray = new SparseArray<>();
}
View view = mViewSparseArray.get(id);
if (view == null) {
view = dialog.findViewById(id);
mViewSparseArray.put(id, view);
}
return view;
}
/** 请空集合 */
private void clean() {
if (mViewSparseArray != null) {
mViewSparseArray.clear();
}
if (mViewIdList != null) {
mViewIdList.clear();
}
if (mArrayContentCallback != null) {
mArrayContentCallback.clear();
}
if (mClickViewIdList != null) {
mClickViewIdList.clear();
}
if (mArrayPositiveClickListener != null) {
mArrayPositiveClickListener.clear();
}
}
/** dp 转为 pix */
private int dp2Pix(int dp) {
final float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
}
HummerDialogStyle
2. 用法
2.1 布局
就四个TextView
2.2 代码
private void showDialog() {
DialogHelper.myBuilder()
.tag("Hummer")
.layoutResId(R.layout.dialog_help_layout) // 布局
.cancelable(false) // back 是否消失
.outCancelable(false) // 点击外部是否消失
.left(0) // 屏幕左边距
.right(0) // 屏幕右边距
.bottom(40) // 屏幕底部边距
.alpha(0.6F) // 透明度
.gravity(Gravity.BOTTOM) // 位于底部
.widget(R.id.dialog_help_tv_title, tv -> {
// 用于改变内部控件内容
String title = "20180901 15:17";
tv.setText(title);
})
.onCancelClick(R.id.dialog_help_tv_cancel) // 点击取消 Dialog
.onCancelClick(R.id.dialog_help_tv_cancel) // 点击取消 Dialog,测试重复添加
.onCancelClick(R.id.dialog_help_tv_title) // 点击取消 Dialog
.autoDismissOnClick(false) // 点击确定事件,是否消失
.onPositiveClick(R.id.dialog_help_tv_ok, dialog -> {
// 点击时,可以通过Dialog.findViewById 来获取控件
TextView tvTitle = dialog.findViewById(R.id.dialog_help_tv_msg);
String msg = tvTitle.getText().toString();
ToastUtils.showShort(msg);
})
.heightLayoutParams(WindowManager.LayoutParams.MATCH_PARENT) // 大部分情况下默认使用 WRAP_CONTENT,必要时修改
.build()
.show(getSupportFragmentManager());
}
两个月来,身体不好,有个感触:
生活终究还是要讲究些的,讲究些,养成好习惯
尽量不把钱花在看病上,一定要注意身体