Android 建造通用的Dialog和PopupWindow

一、Builder设计模式的定义
将一个复杂对象的构建和它的表现分离,使得同样的构建过程,可以创建不同的表示。
建造步骤:
1. 明确建造的对象,如QuickDialog、QuickPopup
2. 确定建造者,如QuickBuild(里面包含建造参数QuickParams)
3. 一些View的辅助类(QuickViewHelper)
二、Android使用系统的Dialog
//1.得到对话框的构造器,可以构造对话的模版
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("标题");
builder.setMessage("包含内容");
//2.添加一个确定按钮
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
//3.添加一个取消按钮
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
//4.使用构造器创建一个对话框的对象
AlertDialog dialog = builder.create();
//5.显示对话框
dialog.show();
三、安际开发情况
由于每个APP的风格不一样,UI设计的弹窗五花八门,系统的Dialog用得不多。系统的Dialog定制性不强等等。
由于系统的Dialog有诸多的不便,自己写一个通用的可定制的Dialog就是必要的了。
四、Dialog都有哪些通用特性?
1.Dialog的显示动画、位置,常用的是由下面出来和中间出来。
2.Dialog的背景,包括背景色、背景圆角。
3.其它的一些设置,用Dialog系统有的就行了,比如取消监听等等
五、Dialog、PopupWindow建造类(QuickBuild ),主要是设置构建的一些参数。
    /**
     * Dialog、PopupWindow 构建器
     */
    public class QuickBuild {
        private Activity mActivity;
        // 默认主题
        private int mTheme = R.style.QuickDialogTheme;
        // 构建Dialog的参数
        private QuickParams mParams;

        public QuickBuild(Activity activity) {
            this.mActivity = activity;
            mParams = new QuickParams(activity);
        }

        public static QuickBuild crate(Activity activity) {
            return new QuickBuild(activity);
        }

        /**
         * 设置主题
         */
        public QuickBuild setTheme(int theme) {
            this.mTheme = theme;
            return this;
        }

        /**
         * 设置宽度
         */
        public QuickBuild setWidth(int width) {
            mParams.mWidth = width;
            return this;
        }

        /**
         * 设置高度
         */
        public QuickBuild setHeight(int height) {
            mParams.mHeight = height;
            return this;
        }

        /**
         * 设置宽高
         */
        public QuickBuild setWidthHeight(int width, int height) {
            mParams.mWidth = width;
            mParams.mHeight = height;
            return this;
        }

        /**
         * 设置布局ID
         */
        public QuickBuild setContentView(int layoutId) {
            mParams.mLayoutId = layoutId;
            return this;
        }

        /**
         * 设置布局View
         */
        public QuickBuild setContentView(View view) {
            mParams.mContentView = view;
            return this;
        }


        /**
         * 设置ContentView背景的颜色:默认白色
         */
        public QuickBuild setBackgroundColor(int color) {
            mParams.mBgColor = color;
            return this;
        }

        /**
         * 设置Window背景
         *
         * @param isSetBg false 就不设置默认圆角
         */
        public QuickBuild isSetBackground(boolean isSetBg) {
            mParams.mIsSetBg = isSetBg;
            return this;
        }

        /**
         * 设置ContentView背景的圆角:默认10dp
         *
         * @param radius 内部已转成dp
         * @return
         */
        public QuickBuild setBackgroundRadius(int radius) {
            mParams.mBgRadius = radius;
            return this;
        }

        /**
         * 设置背景是否模糊:默认是模糊的
         *
         * @param isDimEnabled
         * @return
         */
        public QuickBuild isDimEnabled(boolean isDimEnabled) {
            mParams.mIsDimEnabled = isDimEnabled;
            return this;
        }

        /**
         * 设置宽度占满的比例
         */
        public QuickBuild setWidthScale(float scale) {
            mParams.mScale = scale;
            return this;
        }

        /**
         * 设置宽度占满
         */
        public QuickBuild setFullWidth() {
            setWidthScale(1.0f);
            return this;
        }

        /**
         * 设置高度占满
         */
        public QuickBuild setFullHeight() {
            mParams.mIsHeightFull = true;
            mParams.mHeight = ViewGroup.LayoutParams.MATCH_PARENT;
            return this;
        }

        /**
         * 从底部弹出
         */
        public QuickBuild fromBottom(boolean isAnim) {
            if (isAnim) {
                mParams.mAnimation = R.style.Anim_Dialog_Bottom;
            }
            mParams.mGravity = Gravity.BOTTOM;
            return this;
        }

        /**
         * 从顶部弹出
         */
        public QuickBuild fromTop(boolean isAnim) {
            if (isAnim) {
                mParams.mAnimation = R.style.Anim_Dialog_Top;
            }
            mParams.mGravity = Gravity.TOP;
            return this;
        }

        /**
         * 设置自定义的弹出动画
         */
        public QuickBuild animation(int resId) {
            mParams.mAnimation = resId;
            return this;
        }


        /**
         * 设置点击空白是否消失
         */
        public QuickBuild cancelable(boolean cancelable) {
            mParams.mCancelable = cancelable;
            return this;
        }

        /**
         * 设置取消的监听
         */
        public QuickBuild setOnCancelListener(DialogInterface.OnCancelListener onCancelListener) {
            mParams.mOnCancelListener = onCancelListener;
            return this;
        }

        /**
         * 设置Dialog消息的监听
         */
        public QuickBuild setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) {
            mParams.mOnDismissListener = onDismissListener;
            return this;
        }

        /**
         * 设置按键的监听
         */
        public QuickBuild setOnKeyListener(DialogInterface.OnKeyListener onKeyListener) {
            mParams.mOnKeyListener = onKeyListener;
            return this;
        }

        /**
         * 根据布局ID设置文本信息
         */
        public QuickBuild setText(int viewId, CharSequence text) {
            mParams.setText(viewId, text);
            return this;
        }

        /**
         * 根据布局ID设置点击事件
         */
        public QuickBuild setOnClickListener(int viewId, View.OnClickListener onClickListener) {
            mParams.setOnClickListener(viewId, onClickListener);
            return this;
        }

        /**
         * 构建Dialog
         */
        public QuickDialog build() {
            QuickDialog dialog = new QuickDialog(mActivity, mTheme);
            dialog.apply(mParams);
            return dialog;
        }

        /**
         * 构建并显示Dialog
         */
        public QuickDialog show() {
            QuickDialog dialog = build();
            dialog.show();
            return dialog;
        }

        /**
         * 构建QuickPopup
         */
        public QuickPopup buildPopup() {
            QuickPopup popup = new QuickPopup(mActivity);
            popup.apply(mParams);
            return popup;
        }


        /**
         * Dialog构建参数
         */
        static class QuickParams {
            // 存放文本的集合
            SparseArray mTextArray = new SparseArray<>();
            // 存放点击事件的集合
            SparseArray mClickArray = new SparseArray<>();
            DialogInterface.OnCancelListener mOnCancelListener;
            DialogInterface.OnDismissListener mOnDismissListener;
            DialogInterface.OnKeyListener mOnKeyListener;
            View mContentView;
            int mLayoutId;
            int mWidth;
            int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
            int mGravity = Gravity.CENTER;
            int mAnimation;
            float mScale = 0.75f;
            int mBgRadius = 5;
            int mBgColor = Color.parseColor("#ffffff");
            boolean mIsSetBg = true;
            boolean mIsDimEnabled = true;
            boolean mCancelable = true;
            //
            boolean mIsHeightFull = false;

            QuickParams(Context context) {
                DisplayMetrics dm = context.getResources().getDisplayMetrics();
                mWidth = (int) Math.floor(dm.widthPixels);
            }

            /**
             * 根据布局ID设置文本信息
             */
            void setText(int viewId, CharSequence text) {
                mTextArray.put(viewId, text);
            }

            /**
             * 根据布局ID设置点击事件
             */
            void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
                mClickArray.put(viewId, onClickListener);
            }
        }

    }
六、View的辅助类,主要是加载View布局和找到里面的View等
/**
 * View显示的辅助类
 */

public class QuickViewHelper {
    private View mContentView;
    private SparseArray> mViews = new SparseArray<>();

    public QuickViewHelper(Context context, int layoutResId) {
        mContentView = LayoutInflater.from(context).inflate(layoutResId, null, false);
    }

    public QuickViewHelper(View mView) {
        mContentView = mView;
    }

    public View getContentView() {
        return mContentView;
    }


    /**
     * 设置文本
     */
    public void setText(int viewId, CharSequence charSequence) {
        TextView tv = getView(viewId);
        if (tv != null && charSequence != null) {
            if (TextUtils.isEmpty(charSequence)) {
                tv.setText("");
                return;
            }
            tv.setText(charSequence);
        }
    }

    public  T getView(int viewId) {
        WeakReference viewWeakReference = mViews.get(viewId);
        View view = null;
        if (viewWeakReference == null) {
            view = mContentView.findViewById(viewId);
            if (view != null) {
                mViews.put(viewId, new WeakReference<>(view));
            }
        } else {
            view = viewWeakReference.get();
        }
        return (T) view;
    }

    /**
     * 设置点击事件
     */
    public void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        View view = getView(viewId);
        if (view != null && onClickListener != null) {
            view.setOnClickListener(onClickListener);
        }
    }
}
七、自定义通用的Dialog
/**
 * 自定义的Dialog
 */

public class QuickDialog extends Dialog {
    private QuickViewHelper viewHelper;


    QuickDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
    }

    /**
     * 根据布局ID设置文本信息
     */
    public QuickDialog setText(int viewId, CharSequence text) {
        if (viewHelper != null) {
            viewHelper.setText(viewId, text);
        }
        return this;
    }

    /**
     * 根据布局ID设置点击事件
     */
    public QuickDialog setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        if (viewHelper != null) {
            viewHelper.setOnClickListener(viewId, onClickListener);
        }
        return this;
    }


    @Override
    public void dismiss() {
        closeKeyboard();
        super.dismiss();
    }


    /**
     * 关闭软键盘
     */
    private void closeKeyboard() {
        View view = getCurrentFocus();
        if (view instanceof TextView) {
            InputMethodManager mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            mInputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);
        }
    }

    public void apply(QuickBuild.QuickParams params) {
        // 1.设置布局
        if (params.mLayoutId != 0) {
            viewHelper = new QuickViewHelper(getContext(), params.mLayoutId);
        }
        if (params.mContentView != null) {
            viewHelper = new QuickViewHelper(params.mContentView);
        }
        if (viewHelper == null) {
            throw new IllegalArgumentException("请调用setContentView方法设置布局");
        }
        View contentView = viewHelper.getContentView();
        setContentView(contentView);

        // 2.设置文本
        int textSize = params.mTextArray.size();
        for (int i = 0; i < textSize; i++) {
            viewHelper.setText(params.mTextArray.keyAt(i), params.mTextArray.valueAt(i));
        }
        // 3.设置点击
        int clickSize = params.mClickArray.size();
        for (int i = 0; i < clickSize; i++) {
            viewHelper.setOnClickListener(params.mClickArray.keyAt(i), params.mClickArray.valueAt(i));
        }

        // 4.设置Window
        Window window = getWindow();
        // 位置
        window.setGravity(params.mGravity);
        // 动画
        if (params.mAnimation != 0) {
            window.setWindowAnimations(params.mAnimation);
        }
        // 宽高
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.width = (int) (params.mWidth * params.mScale);
        lp.height = params.mHeight;
        window.setAttributes(lp);
        // 设置Window背景
        if (params.mIsSetBg) {
            final GradientDrawable bg = new GradientDrawable();
            int radius = dp2px(getContext(), params.mBgRadius);
            // 1 2 3 4(顺时针)
            bg.setCornerRadii(new float[]{radius, radius, radius, radius, radius, radius, radius, radius});
            bg.setColor(params.mBgColor);
            window.setBackgroundDrawable(bg);
        }

        // 设置背景是否模糊
        if (!params.mIsDimEnabled) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                window.setDimAmount(0f);
            }
        }

        // 设置外面能不能点击
        setCancelable(params.mCancelable);
        setCanceledOnTouchOutside(params.mCancelable);
        // 设置事件监听
        setOnCancelListener(params.mOnCancelListener);
        setOnDismissListener(params.mOnDismissListener);
        setOnKeyListener(params.mOnKeyListener);
    }

    public static int dp2px(Context context, float dp) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }
}
八、 自定义PopupWindow
/**
 * 自定义的PopupWindow
 */

public class QuickPopup extends PopupWindow {
    private QuickViewHelper viewHelper;
    private Activity mActivity;

    public QuickPopup(Activity activity) {
        super(activity);
        this.mActivity = activity;
    }

    /**
     * 根据布局ID设置文本信息
     */
    public QuickPopup setText(int viewId, CharSequence text) {
        if (viewHelper != null) {
            viewHelper.setText(viewId, text);
        }
        return this;
    }

    /**
     * 根据布局ID设置点击事件
     */
    public QuickPopup setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        if (viewHelper != null) {
            viewHelper.setOnClickListener(viewId, onClickListener);
        }
        return this;
    }


    @Override
    public void dismiss() {
        // 关闭键盘
        closeKeyboard();
        // 背景还原
        setWindowDim(mActivity, false);
        super.dismiss();
    }


    /**
     * 关闭软键盘
     */
    private void closeKeyboard() {
        if (mActivity == null) {
            return;
        }
        View view = mActivity.getCurrentFocus();
        if (view instanceof TextView) {
            InputMethodManager mInputMethodManager = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
            mInputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);
        }
    }

    public void apply(QuickBuild.QuickParams params) {
        // 1.设置布局
        if (params.mLayoutId != 0) {
            viewHelper = new QuickViewHelper(mActivity, params.mLayoutId);
        }
        if (params.mContentView != null) {
            viewHelper = new QuickViewHelper(params.mContentView);
        }
        if (viewHelper == null) {
            throw new IllegalArgumentException("请调用setContentView方法设置布局");
        }
        View contentView = viewHelper.getContentView();
        measureView(contentView);
        setContentView(contentView);

        // 设置宽高
        if (params.mWidth > 0) {
            setWidth(params.mWidth);
        } else {
            setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        if (params.mHeight > 0) {
            setHeight(params.mHeight);
        } else {
            setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        if (params.mIsHeightFull) {
            setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        }

        setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        setOutsideTouchable(params.mCancelable);
        setFocusable(params.mCancelable);
        // 动画
        if (params.mAnimation != 0) {
            setAnimationStyle(params.mAnimation);
        }


        // 2.设置文本
        int textSize = params.mTextArray.size();
        for (int i = 0; i < textSize; i++) {
            viewHelper.setText(params.mTextArray.keyAt(i), params.mTextArray.valueAt(i));
        }
        // 3.设置点击
        int clickSize = params.mClickArray.size();
        for (int i = 0; i < clickSize; i++) {
            viewHelper.setOnClickListener(params.mClickArray.keyAt(i), params.mClickArray.valueAt(i));
        }
        // 背景模糊
        if (params.mIsDimEnabled) {
            setWindowDim(mActivity, true);
        }
    }

    /**
     * 测量View的宽高
     *
     * @param view View
     */
    private void measureView(View view) {
        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        view.measure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 给整个屏幕添加阴影背景
     *
     * @param activity
     * @param isDim    TRUE  添加  false 不添加
     */
    public void setWindowDim(Activity activity, boolean isDim) {
        if (null != activity) {
            WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
            lp.alpha = isDim ? .7f : 1.0f;
            if (isDim) {
                activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            } else {
                activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            }
            activity.getWindow().setAttributes(lp);
        }
    }
    
}
七、Dialog默认显示的主题
 
    



    
    




    
    

八、Dialog的使用
QuickDialog dialog = QuickBuild.create(this)
        .setContentView(R.layout.dialog_loading)
        .fromBottom(true)
        .setCancelable(false)
        .setIsDimEnabled(false)
        .build();
        // 设置Dialog布局里面View的点击事件,文本设置一样
        dialog.setOnClickListener(R.id.dialog_message, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });
        dialog.show();
    1. 用起来感觉简单多了,也可以根据UI定制一些APP通用的Dialog。
    1. 整合了Dialog和PopupWindow,开发更为方便一些。
      简化后的源码地址:https://github.com/wenkency/DesignPattern

你可能感兴趣的:(Android 建造通用的Dialog和PopupWindow)