Android 建造通用的Dialog和PopupWindow

一、Builder設(shè)計(jì)模式的定義
將一個復(fù)雜對象的構(gòu)建和它的表現(xiàn)分離,使得同樣的構(gòu)建過程,可以創(chuàng)建不同的表示。
建造步驟:
1. 明確建造的對象,如QuickDialog、QuickPopup
2. 確定建造者,如QuickBuild(里面包含建造參數(shù)QuickParams)
3. 一些View的輔助類(QuickViewHelper)
二、Android使用系統(tǒng)的Dialog
//1.得到對話框的構(gòu)造器,可以構(gòu)造對話的模版
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("標(biāo)題");
builder.setMessage("包含內(nèi)容");
//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.使用構(gòu)造器創(chuàng)建一個對話框的對象
AlertDialog dialog = builder.create();
//5.顯示對話框
dialog.show();
三、安際開發(fā)情況
由于每個APP的風(fēng)格不一樣,UI設(shè)計(jì)的彈窗五花八門,系統(tǒng)的Dialog用得不多。系統(tǒng)的Dialog定制性不強(qiáng)等等。
由于系統(tǒng)的Dialog有諸多的不便,自己寫一個通用的可定制的Dialog就是必要的了。
四、Dialog都有哪些通用特性?
1.Dialog的顯示動畫、位置,常用的是由下面出來和中間出來。
2.Dialog的背景,包括背景色、背景圓角。
3.其它的一些設(shè)置,用Dialog系統(tǒng)有的就行了,比如取消監(jiān)聽等等
五、Dialog、PopupWindow建造類(QuickBuild ),主要是設(shè)置構(gòu)建的一些參數(shù)。
    /**
     * Dialog、PopupWindow 構(gòu)建器
     */
    public class QuickBuild {
        private Activity mActivity;
        // 默認(rèn)主題
        private int mTheme = R.style.QuickDialogTheme;
        // 構(gòu)建Dialog的參數(shù)
        private QuickParams mParams;

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

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

        /**
         * 設(shè)置主題
         */
        public QuickBuild setTheme(int theme) {
            this.mTheme = theme;
            return this;
        }

        /**
         * 設(shè)置寬度
         */
        public QuickBuild setWidth(int width) {
            mParams.mWidth = width;
            return this;
        }

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

        /**
         * 設(shè)置寬高
         */
        public QuickBuild setWidthHeight(int width, int height) {
            mParams.mWidth = width;
            mParams.mHeight = height;
            return this;
        }

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

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


        /**
         * 設(shè)置ContentView背景的顏色:默認(rèn)白色
         */
        public QuickBuild setBackgroundColor(int color) {
            mParams.mBgColor = color;
            return this;
        }

        /**
         * 設(shè)置Window背景
         *
         * @param isSetBg false 就不設(shè)置默認(rèn)圓角
         */
        public QuickBuild isSetBackground(boolean isSetBg) {
            mParams.mIsSetBg = isSetBg;
            return this;
        }

        /**
         * 設(shè)置ContentView背景的圓角:默認(rèn)10dp
         *
         * @param radius 內(nèi)部已轉(zhuǎn)成dp
         * @return
         */
        public QuickBuild setBackgroundRadius(int radius) {
            mParams.mBgRadius = radius;
            return this;
        }

        /**
         * 設(shè)置背景是否模糊:默認(rèn)是模糊的
         *
         * @param isDimEnabled
         * @return
         */
        public QuickBuild isDimEnabled(boolean isDimEnabled) {
            mParams.mIsDimEnabled = isDimEnabled;
            return this;
        }

        /**
         * 設(shè)置寬度占滿的比例
         */
        public QuickBuild setWidthScale(float scale) {
            mParams.mScale = scale;
            return this;
        }

        /**
         * 設(shè)置寬度占滿
         */
        public QuickBuild setFullWidth() {
            setWidthScale(1.0f);
            return this;
        }

        /**
         * 設(shè)置高度占滿
         */
        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;
        }

        /**
         * 設(shè)置自定義的彈出動畫
         */
        public QuickBuild animation(int resId) {
            mParams.mAnimation = resId;
            return this;
        }


        /**
         * 設(shè)置點(diǎn)擊空白是否消失
         */
        public QuickBuild cancelable(boolean cancelable) {
            mParams.mCancelable = cancelable;
            return this;
        }

        /**
         * 設(shè)置取消的監(jiān)聽
         */
        public QuickBuild setOnCancelListener(DialogInterface.OnCancelListener onCancelListener) {
            mParams.mOnCancelListener = onCancelListener;
            return this;
        }

        /**
         * 設(shè)置Dialog消息的監(jiān)聽
         */
        public QuickBuild setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) {
            mParams.mOnDismissListener = onDismissListener;
            return this;
        }

        /**
         * 設(shè)置按鍵的監(jiān)聽
         */
        public QuickBuild setOnKeyListener(DialogInterface.OnKeyListener onKeyListener) {
            mParams.mOnKeyListener = onKeyListener;
            return this;
        }

        /**
         * 根據(jù)布局ID設(shè)置文本信息
         */
        public QuickBuild setText(int viewId, CharSequence text) {
            mParams.setText(viewId, text);
            return this;
        }

        /**
         * 根據(jù)布局ID設(shè)置點(diǎn)擊事件
         */
        public QuickBuild setOnClickListener(int viewId, View.OnClickListener onClickListener) {
            mParams.setOnClickListener(viewId, onClickListener);
            return this;
        }

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

        /**
         * 構(gòu)建并顯示Dialog
         */
        public QuickDialog show() {
            QuickDialog dialog = build();
            dialog.show();
            return dialog;
        }

        /**
         * 構(gòu)建QuickPopup
         */
        public QuickPopup buildPopup() {
            QuickPopup popup = new QuickPopup(mActivity);
            popup.apply(mParams);
            return popup;
        }


        /**
         * Dialog構(gòu)建參數(shù)
         */
        static class QuickParams {
            // 存放文本的集合
            SparseArray<CharSequence> mTextArray = new SparseArray<>();
            // 存放點(diǎn)擊事件的集合
            SparseArray<View.OnClickListener> 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);
            }

            /**
             * 根據(jù)布局ID設(shè)置文本信息
             */
            void setText(int viewId, CharSequence text) {
                mTextArray.put(viewId, text);
            }

            /**
             * 根據(jù)布局ID設(shè)置點(diǎn)擊事件
             */
            void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
                mClickArray.put(viewId, onClickListener);
            }
        }

    }
六、View的輔助類,主要是加載View布局和找到里面的View等
/**
 * View顯示的輔助類
 */

public class QuickViewHelper {
    private View mContentView;
    private SparseArray<WeakReference<View>> 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;
    }


    /**
     * 設(shè)置文本
     */
    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 extends View> T getView(int viewId) {
        WeakReference<View> 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;
    }

    /**
     * 設(shè)置點(diǎn)擊事件
     */
    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);
    }

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

    /**
     * 根據(jù)布局ID設(shè)置點(diǎn)擊事件
     */
    public QuickDialog setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        if (viewHelper != null) {
            viewHelper.setOnClickListener(viewId, onClickListener);
        }
        return this;
    }


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


    /**
     * 關(guān)閉軟鍵盤
     */
    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.設(shè)置布局
        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("請調(diào)用setContentView方法設(shè)置布局");
        }
        View contentView = viewHelper.getContentView();
        setContentView(contentView);

        // 2.設(shè)置文本
        int textSize = params.mTextArray.size();
        for (int i = 0; i < textSize; i++) {
            viewHelper.setText(params.mTextArray.keyAt(i), params.mTextArray.valueAt(i));
        }
        // 3.設(shè)置點(diǎn)擊
        int clickSize = params.mClickArray.size();
        for (int i = 0; i < clickSize; i++) {
            viewHelper.setOnClickListener(params.mClickArray.keyAt(i), params.mClickArray.valueAt(i));
        }

        // 4.設(shè)置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);
        // 設(shè)置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);
        }

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

        // 設(shè)置外面能不能點(diǎn)擊
        setCancelable(params.mCancelable);
        setCanceledOnTouchOutside(params.mCancelable);
        // 設(shè)置事件監(jiān)聽
        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;
    }

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

    /**
     * 根據(jù)布局ID設(shè)置點(diǎn)擊事件
     */
    public QuickPopup setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        if (viewHelper != null) {
            viewHelper.setOnClickListener(viewId, onClickListener);
        }
        return this;
    }


    @Override
    public void dismiss() {
        // 關(guān)閉鍵盤
        closeKeyboard();
        // 背景還原
        setWindowDim(mActivity, false);
        super.dismiss();
    }


    /**
     * 關(guān)閉軟鍵盤
     */
    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.設(shè)置布局
        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("請調(diào)用setContentView方法設(shè)置布局");
        }
        View contentView = viewHelper.getContentView();
        measureView(contentView);
        setContentView(contentView);

        // 設(shè)置寬高
        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.設(shè)置文本
        int textSize = params.mTextArray.size();
        for (int i = 0; i < textSize; i++) {
            viewHelper.setText(params.mTextArray.keyAt(i), params.mTextArray.valueAt(i));
        }
        // 3.設(shè)置點(diǎn)擊
        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默認(rèn)顯示的主題
 <!--從下彈出來的基本動畫-->
    <style name="Anim_Dialog_Bottom" parent="@style/Theme.AppCompat.Dialog">
        <item name="android:windowEnterAnimation">@anim/slide_in</item>
        <item name="android:windowExitAnimation">@anim/slide_out</item>
    </style>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--slide_in-->
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:fromYDelta="100%"
        android:toXDelta="0"
        android:toYDelta="0" />
</set>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--slide_out-->
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="100%" />
</set>
八、Dialog的使用
QuickDialog dialog = QuickBuild.create(this)
        .setContentView(R.layout.dialog_loading)
        .fromBottom(true)
        .setCancelable(false)
        .setIsDimEnabled(false)
        .build();
        // 設(shè)置Dialog布局里面View的點(diǎn)擊事件,文本設(shè)置一樣
        dialog.setOnClickListener(R.id.dialog_message, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });
        dialog.show();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容