美文网首页
Dialog 辅助工具

Dialog 辅助工具

作者: 英勇青铜5 | 来源:发表于2018-09-01 15:43 被阅读194次

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.png

2.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();
    }

两个月来,身体不好,有个感触:

生活终究还是要讲究些的,讲究些,养成好习惯

尽量不把钱花在看病上,一定要注意身体

相关文章

  • Dialog 辅助工具

    1. DialogHelper 这不是一个自定义的Dialog,而是一个Helper,一开始想这个Helper的目...

  • Dialog充满屏幕

    Dialog宽高设置 dialog style_dialog dialog_animation enter exi...

  • 水彩进阶教程-辅助工具认识

    水彩辅助工具-调色盘 水彩辅助工具-高光笔、海绵 水彩辅助工具-盐 水彩辅助工具-喷瓶 水彩辅助工具-橡皮 水彩辅...

  • 全屏Dialog示例

    final Dialog dialog = new Dialog(context,R.style.weightin...

  • Dialog 出现消失动画和位置

    Dialog 的动画 拿到Dialog的实例,dialog.getWindow().getAttributes()...

  • Android圆角对话框Dialog

    需求:模仿iOS样式Dialog对话框。 自定义Dialog 核心代码: Dialog样式: Dialog布局文件...

  • 微信小程序,实现简易弹窗组件

    1、组件实现相关文件和代码: dialog.js dialog.json dialog.wxml dialog.w...

  • Dialog

    安卓dialog的使用+如何自定义dialog自定义Dialog自定义Dialog 自定义

  • Flutter Dialog 动画

    本文对 Dialog 做一次系统性学习记录,包括系统 Dialog,自定义 Dialog,Dialog 动画。 A...

  • dialog 不消失

    dialog弹出后会点击屏幕或物理返回键,dialog不消失 dialog弹出后会点击屏幕,dialog不消失;点...

网友评论

      本文标题:Dialog 辅助工具

      本文链接:https://www.haomeiwen.com/subject/jdruwftx.html