Dialog 辅助工具

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. 用法

Dialog 辅助工具_第1张图片
dialog.png

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

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

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

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

你可能感兴趣的:(Dialog 辅助工具)