1. DialogHelper
这不是一个自定义的Dialog
,而是一个Helper
,一开始想这个Helper
的目的侧重于配置组装Dialog
,而尽量少的改变Dialog
属性
项目中一共有10几个不同布局的Dialog
,里面输入、点击、选择不同的事件都有,想要使用一个Dialog
来满足所有的需求比较麻烦,一开始考虑的是写一个BaseDialog
,之后根据各个Dialog
来继承实现,然而还要写不同事件的接口回调,觉得继承BaseDialg
也比较麻烦,想着写一个简单能满足基础需求类似Utils
的东西
一开始考虑使用Builder
的方式比较好
网上搜索时,看到利用建造者模式封装一个简单好用的dialog,但这个虽然标题写的叫建造者
,但代码用的是单例
,个人感觉使用单例
不怎么合适,借鉴思路自己整理出来一个
希望各位同学能给出一些更好的思路
public class DialogHelper implements LifecycleObserver {
private static final String TAG = DialogHelper.class.getSimpleName();
private final Context mContext;
private final int mLayoutId;
private final int mGravity;
private final int mPaddingTop;
private final int mPaddingBottom;
private final int mPaddingRight;
private final int mPaddingLeft;
private final boolean mCancelable;
private final boolean mOutCancelable;
private final List<Integer> mViewIdList;
private final SparseArray<OnSetViewContentCallback> mArrayContentCallback;
private final List<Integer> mClickViewIdList;
private final SparseArray<OnViewClickListener> mArrayPositiveClickListener;
private final boolean mAutoDismissAble;
private Dialog mDialog;
private SparseArray<View> mViewSparseArray;
public DialogHelper(Builder builder) {
mContext = builder.mContext;
mLayoutId = builder.mLayoutId;
mGravity = builder.mGravity;
mPaddingTop = dp2Pix(builder.mPaddingTop);
mPaddingLeft = dp2Pix(builder.mPaddingLeft);
mPaddingBottom = dp2Pix(builder.mPaddingBottom);
mPaddingRight = dp2Pix(builder.mPaddingRight);
mCancelable = builder.mCancelable;
mOutCancelable = builder.mOutCancelable;
mViewIdList = builder.mViewIdList;
mArrayContentCallback = builder.mArrayContentCallback;
mClickViewIdList = builder.mClickViewIdList;
mArrayPositiveClickListener = builder.mArrayPositiveClickListener;
mAutoDismissAble = builder.mAutoDismissAble;
if (builder.mOwner != null) {
builder.mOwner.getLifecycle().addObserver(this);
}
}
public void show() {
if (mDialog == null) {
initDialog();
}
mDialog.show();
}
public void dismiss() {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
dismiss();
}
/**
* 初始化 Dialog
*/
private void initDialog() {
mDialog = new Dialog(mContext);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setCancelable(mCancelable);
mDialog.setCanceledOnTouchOutside(mOutCancelable);
mDialog.setContentView(mLayoutId);
Window window = mDialog.getWindow();
if (window == null) {
return;
}
// 窗口背景设置为透明
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.setGravity(mGravity);
window.getDecorView().setPadding(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
WindowManager.LayoutParams lp = window.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
// 监听
initSetContentCallback();
initClickListener();
}
/**
* 改变内部 View 内容回调
*/
private void initSetContentCallback() {
if (mViewIdList == null || mArrayContentCallback == null) {
return;
}
for (int i : mViewIdList) {
View view = getViewById(i);
if (view == null) {
throw new NullPointerException("设置 View 内容, 内部 View 没有找到");
}
mArrayContentCallback.get(i).setViewContent(view);
}
}
/**
* 点击事件回调
*/
private void initClickListener() {
if (mClickViewIdList == null) {
return;
}
for (int i : mClickViewIdList) {
View view = getViewById(i);
if (view == null) {
throw new NullPointerException("点击回调, 内部 View 没有找到");
}
view.setOnClickListener(v -> {
// 是否自动 dismiss
boolean isAutoDis = mAutoDismissAble || (mArrayPositiveClickListener == null) ||
(mArrayPositiveClickListener.get(i) == null);
if (isAutoDis) {
// 当 mArrayPositiveClickListener == null
// mArrayPositiveClickListener.get(i) 为 null,说明当前 id 为点击取消事件
dismiss();
}
if (mArrayPositiveClickListener != null && mArrayPositiveClickListener.get(i) != null) {
mArrayPositiveClickListener.get(i).setPositiveClick(mDialog);
}
});
}
}
/**
* 根据 id 获取 view
*
* @param id id
* @return view
*/
private View getViewById(int id) {
if (mViewSparseArray == null) {
mViewSparseArray = new SparseArray<>();
}
View view = mViewSparseArray.get(id);
if (view == null) {
view = mDialog.findViewById(id);
mViewSparseArray.put(id, view);
}
return view;
}
private int dp2Pix(int dp) {
final float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
public static class Builder {
private Context mContext;
private LifecycleOwner mOwner;
/**
* 布局 ID
*/
private int mLayoutId;
/**
* 弹窗 Gravity 值
* 默认 中心
*/
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<Integer> mViewIdList;
private SparseArray<OnSetViewContentCallback> mArrayContentCallback;
/**
* 点击事件
*/
private List<Integer> mClickViewIdList;
private SparseArray<OnViewClickListener> mArrayPositiveClickListener;
/**
* 点击事件是否需要自动消失
* 默认 true
*/
private boolean mAutoDismissAble = true;
/**
* 上下文
*/
public Builder context(@NonNull Context context) {
this.mContext = context;
return this;
}
/**
* LifecycleOwner
*/
public Builder lifecycleOwner(@NonNull LifecycleOwner owner) {
this.mOwner = owner;
return this;
}
/**
* 布局 ID
*/
public Builder layoutResId(@LayoutRes int layoutId) {
this.mLayoutId = layoutId;
return this;
}
/**
* 位置
*/
public Builder gravity(int gravity) {
this.mGravity = gravity;
return this;
}
/**
* 内边距
*/
public Builder padding(int padding) {
paddingLeft(padding);
paddingTop(padding);
paddingRight(padding);
paddingBottom(padding);
return this;
}
/**
* Top 内边距
*/
public Builder paddingTop(int paddingTop) {
this.mPaddingTop = paddingTop;
return this;
}
/**
* Left 内边距
*/
public Builder paddingLeft(int paddingLeft) {
this.mPaddingLeft = paddingLeft;
return this;
}
/**
* Bottom 内边距
*/
public Builder paddingBottom(int paddingBottom) {
this.mPaddingBottom = paddingBottom;
return this;
}
/**
* Right 内边距
*/
public Builder paddingRight(int paddingRight) {
this.mPaddingRight = paddingRight;
return this;
}
/**
* 设置 back 键是否可以取消
*/
public Builder cancelable(boolean cancelable) {
this.mCancelable = cancelable;
return this;
}
/**
* 点击外部是否可以取消
*/
public Builder outCancelable(boolean outCancelable) {
this.mOutCancelable = outCancelable;
return this;
}
/**
* 改变内部 View 内容
*/
public Builder viewContent(@IdRes int id,
@NonNull OnSetViewContentCallback onSetViewContentCallback) {
if (mViewIdList == null) {
mViewIdList = new ArrayList<>();
}
mViewIdList.add(id);
if (mArrayContentCallback == null) {
mArrayContentCallback = new SparseArray<>();
}
this.mArrayContentCallback.put(id, onSetViewContentCallback);
return this;
}
/**
* 点击取消事件
*/
public Builder onCancelClick(@IdRes int id) {
if (mClickViewIdList == null) {
mClickViewIdList = new ArrayList<>();
}
mClickViewIdList.add(id);
return this;
}
/**
* 点击事件
*/
public Builder onPositiveClick(@IdRes int id,
@NonNull OnViewClickListener onViewClickListener) {
if (mClickViewIdList == null) {
mClickViewIdList = new ArrayList<>();
}
mClickViewIdList.add(id);
if (mArrayPositiveClickListener == null) {
mArrayPositiveClickListener = new SparseArray<>();
}
this.mArrayPositiveClickListener.put(id, onViewClickListener);
return this;
}
/**
* 点击时,是否自动关闭
*/
public Builder autoDismissOnClick(boolean auto) {
this.mAutoDismissAble = auto;
return this;
}
public DialogHelper build() {
return new DialogHelper(this);
}
}
/**
* 改变 View 内容
*/
public interface OnSetViewContentCallback {
/**
* View 内容
*
* @param v view
*/
void setViewContent(View v);
}
/**
* 点击监听
* dialog 用来获取内部控件用,findViewById()
*/
public interface OnViewClickListener {
/**
* View 点击
*
* @param dialog 弹窗
*/
void setPositiveClick(Dialog dialog);
}
}
LifecycleObserver
主要是用来感知Activity
的生命周期,前提项目中的Activity
继承自AppCompatActivity
,若用不到,可以把相关的几行代码去掉
2. 用法
dialog.png2.1 布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="180dp"
android:background="@color/lighter_gray">
<TextView
android:id="@+id/dialog_help_tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/dialog_helper_name"
android:textColor="@color/colorPrimary"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/dialog_help_tv_cancel"
android:layout_width="100dp"
android:layout_height="44dp"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="@string/button_cancel"
android:textColor="@color/write"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/dialog_help_tv_ok"
android:layout_width="100dp"
android:layout_height="44dp"
android:background="@color/colorAccent"
android:gravity="center"
android:text="@string/button_ok"
android:textColor="@color/write"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.8"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/dialog_help_tv_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="@string/dialog_helper_name"
android:textColor="@color/colorPrimary"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>
就四个TextView
2.2 代码
private void showDialog() {
new DialogHelper.Builder()
.context(this) // 上下文
.lifecycleOwner(this) // lifecycleOwner
.layoutResId(R.layout.dialog_help_layout) // 布局
.cancelable(false) // back 键是否消失
.outCancelable(false) // 点击外部是否消失
.paddingLeft(0) // 屏幕左边距
.paddingRight(0) // 屏幕右边距
.paddingBottom(40) // 屏幕底部边距
.gravity(Gravity.BOTTOM) // 位于底部
.viewContent(R.id.dialog_help_tv_title, v -> {
// 用于设置或者改变内部控件内容
TextView tvTitle = (TextView) v;
String title = "20180901 15:17";
tvTitle.setText(title);
})
.onCancelClick(R.id.dialog_help_tv_cancel) // 点击取消 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();
Toast.makeText(DialogHelperActivity.this, msg, Toast.LENGTH_LONG).show();
})
.build()
.show();
}
两个月来,身体不好,有个感触:
生活终究还是要讲究些的,讲究些,养成好习惯
尽量不把钱花在看病上,一定要注意身体
网友评论