Builder设计模式构建万能Dialog

首先看下AlertDialog解析图

Builder设计模式构建万能Dialog

首先要会用AlertDialog的使用

new AlertDialog.Builder(this)
    .setIcon(R.mipmap.ic_launcher)
    .setTitle("消息")
    .setPositiveButton("确定", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {

        }
    })
    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {

        }
    })
    .create().show();
对源码解析我们可以得到上图的结果,接下来就是自定义一个Dialog,因为我在我的代码中写了很多注解我就不解释了

第一步自定义一个AlertDialog

public class AlertDialog extends Dialog {
    AlertController mAlert;

    public AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, themeResId);
        mAlert = new AlertController(this, getWindow());
    }




    public void setText(int viewId, CharSequence text) {
        mAlert.setText(viewId, text);
    }

    public void setOnClickListener(int viewId, View.OnClickListener listener) {
        mAlert.setOnClickListener(viewId, listener);
    }


    /**
     * 减少findviewById的次数
     */
    public <T extends View> T getView(int viewId) {

        return mAlert.getView(viewId);
    }

    public static class Builder {

        private final AlertController.AlertParams P;

        public Builder(@NonNull Context context) {
            this(context, R.style.dialog);

        }

        public Builder(@NonNull Context context, @StyleRes int themeResId) {
            P = new AlertController.AlertParams(context, themeResId);
        }

        public AlertDialog create() {
            final AlertDialog dialog = new AlertDialog(P.mContext, P.themeResId);
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }

        /**
         * 设置View
         */
        public AlertDialog.Builder setContentView(int layoutResId) {
            P.mView = null;
            P.mViewLayoutResId = layoutResId;
            return this;
        }

        public AlertDialog.Builder setContentView(View view) {
            P.mView = view;
            P.mViewLayoutResId = 0;
            return this;
        }

        /**
         * 存放自定义View中的文本
         */
        public AlertDialog.Builder setText(int layoutId, CharSequence text) {
            P.mTextArray.put(layoutId, text);
            return this;
        }

        /**
         * 存放自定义View中按钮点击事件
         */
        public AlertDialog.Builder setOnClickListener(int layoutId, View.OnClickListener listener) {
            P.mClickArray.put(layoutId, listener);
            return this;
        }


        //配置一些万能参数
        public AlertDialog.Builder fullWidth() {
            P.mWidth = ViewGroup.LayoutParams.MATCH_PARENT;
            return this;
        }

        //设置动画
        public AlertDialog.Builder fromButtom(boolean isAnimation) {
            if (isAnimation) {
                P.mAnimation = R.style.dialog_from_bottom_anim;
            }
            P.mGravity = Gravity.BOTTOM;
            return this;
        }

        public AlertDialog.Builder setWidthAndHeight(int width, int heigth) {
            P.mWidth = width;
            P.mHeigth = heigth;
            return this;
        }

        //设置默认动画
        public AlertDialog.Builder AddDefaultAnimation() {
            P.mAnimation = R.style.dialog_scale_animation;
            return this;
        }

        //设置动画
        public AlertDialog.Builder setAnimation(int styleAnimation) {
            P.mAnimation = styleAnimation;
            return this;
        }

        public AlertDialog show() {
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }
    }
}
第二步:自定义一个AlertContorller

class AlertController {
    private Window mWindow;
    private AlertDialog mAlertDialog;
    private ViewHelper mViewHelper;

    public AlertController(AlertDialog alertDialog, Window window) {
        this.mWindow = window;
        this.mAlertDialog = alertDialog;
    }

    public void setViewHelper(ViewHelper mViewHelper) {
        this.mViewHelper = mViewHelper;
    }

    public Window getWindow() {
        return mWindow;
    }

    public AlertDialog getDialog() {
        return mAlertDialog;
    }

    public void setText(int viewId, CharSequence text) {
        mViewHelper.setText(viewId,text);
    }

    public void setOnClickListener(int viewId, View.OnClickListener listener) {
        mViewHelper.setOnClickListener(viewId,listener);
    }


    /**
     * 减少findviewById的次数
     */
    public <T extends View> T getView(int viewId) {
     return mViewHelper.getView(viewId);
    }

    public static class AlertParams {
        public Context mContext;
        public int themeResId;
        public boolean mCancelable = true;//点击空白是否能够取消
        public DialogInterface.OnCancelListener mOnCancelListener;//dialog Cancel监听
        public DialogInterface.OnDismissListener mOnDismissListener;//dialog Dismiss监听
        public DialogInterface.OnKeyListener mOnKeyListener;//按键监听
        //View加载布局
        public View mView;
        //id加载布局
        public int mViewLayoutResId;
        //存放自定义view中的文本
        SparseArray<CharSequence> mTextArray = new SparseArray<>();
        //存放自定义view中的点击事件
        SparseArray<View.OnClickListener> mClickArray = new SparseArray<>();
        public int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
        public int mGravity = Gravity.CENTER;
        public int mAnimation;
        public int mHeigth = ViewGroup.LayoutParams.WRAP_CONTENT;

        public AlertParams(Context context, int themeResId) {
            this.mContext = context;
            this.themeResId = themeResId;
        }

        /**
         * 绑定和设置参数
         *
         * @param mAlert
         */
        public void apply(AlertController mAlert) {
            //设置参数
            //1.设置布局
            ViewHelper viewHelper = null;
            if (mViewLayoutResId != 0) {
                viewHelper = new ViewHelper(mContext, mViewLayoutResId);
            }
            if (mView != null) {
                viewHelper = new ViewHelper();
                viewHelper.setContentView(mView);
            }
            if (viewHelper == null) {
                throw new IllegalArgumentException("请设置布局setContentView()");
            }
            //给dialog设置布局
            mAlert.getDialog().setContentView(viewHelper.getContentView());
            //2.设置文本
            int textArraysize = mTextArray.size();
            for (int i = 0; i < textArraysize; i++) {
                viewHelper.setText(mTextArray.keyAt(i), mTextArray.valueAt(i));
            }
            //3.设置点击事件
            int clickSize = mClickArray.size();
            for (int i = 0; i < clickSize; i++) {
                viewHelper.setOnClickListener(mClickArray.keyAt(i), mClickArray.valueAt(i));
            }

            mAlert.setViewHelper(viewHelper);
            //4.配置自定义效果 全屏  从底部弹出 默认动画
            Window window = mAlert.getWindow();
            //设置位置
            window.setGravity(mGravity);
            //设置动画
            if (mAnimation != 0) {
                window.setWindowAnimations(mAnimation);
            }
            //设置宽和高
            WindowManager.LayoutParams params = window.getAttributes();
            params.width = mWidth;
            params.height = mHeigth;
            window.setAttributes(params);
        }
    }
}
第三步:自定义一个ViewHelper

public class ViewHelper {
    private View mContentView;//布局View
    //减少findviewById
    private SparseArray<WeakReference<View>> mViews;

    public ViewHelper(Context context, int viewLayoutResId) {
        this();//此方法不可少,调用的是无参ViewHelper
        mContentView = LayoutInflater.from(context).inflate(viewLayoutResId, null);
    }

    public ViewHelper() {
        mViews = new SparseArray<>();

    }

    public void setContentView(View contentView) {
        this.mContentView = contentView;
    }

    public void setText(int viewId, CharSequence text) {
        TextView tv = getView(viewId);
        if (tv != null) {
           tv.setText(text);
        }
    }

    public void setOnClickListener(int viewId, View.OnClickListener listener) {
        View view = getView(viewId);
        if(view!=null){
            view.setOnClickListener(listener);
        }
    }

    public View getContentView() {
        return mContentView;
    }

    /**
     * 减少findviewById的次数
     */
    public <T extends View> T getView(int viewId) {
        WeakReference<View> weakReference = mViews.get(viewId);
        View view = null;
        if(weakReference!=null){
            view=weakReference.get();
        }
        if (view == null) {
            view = mContentView.findViewById(viewId);
            if (view != null) {
                mViews.put(viewId, new WeakReference<>(view));
            }
        }
        return (T) view;
    }
}
最后这里写下我自己使用的样式和布局

①dialog的样式

<style name="dialog" parent="@android:style/Theme.Dialog">
    <!--没有边框-->
    <item name="android:windowFrame">@null</item>
    <!--是否悬浮在activity之上-->
    <item name="android:windowIsFloating">true</item>
    <!--没有标题-->
    <item name="android:windowIsTranslucent">true</item>
    <!--背景透明-->
    <item name="android:background">@android:color/transparent</item>
    <!--模糊-->
    <item name="android:backgroundDimEnabled">true</item>
    <!--没有标题-->
    <item name="android:windowNoTitle">true</item>
</style>
②进入时的动画

<style name="dialog_from_bottom_anim">
    <item name="android:windowEnterAnimation">@anim/dialog_from_bottom_anim_in</item>
    <item name="android:windowExitAnimation">@anim/dialog_from_bottom_anim_out</item>
</style>

③默认缩放动画

<style name="dialog_scale_anim">
    <item name="android:windowEnterAnimation">@anim/dialog_scale_anim_in</item>
    <item name="android:windowExitAnimation">@anim/dialog_scale_anim_out</item>
</style>

dialog_from_bottom_anim_in:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="0"
        android:fromYDelta="1000"
        android:toYDelta="0"
        android:toXDelta="0" />
</set>
dialog_from_bottom_anim_out:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toYDelta="1000"/>
</set>

dialog_scale_anim_in:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <scale
        android:duration="135"
        android:fromXScale="0.8"
        android:fromYScale="0.8"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.05"
        android:toYScale="1.05" />
    
    <scale
        android:duration="105"
        android:fromXScale="1.05"
        android:fromYScale="1.05"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="135"
        android:toXScale="0.95"
        android:toYScale="0.95" />
    
    <scale
        android:duration="60"
        android:fromXScale="0.95"
        android:fromYScale="0.95"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="240"
        android:toXScale="1.0"
        android:toYScale="1.0" />
    
    <alpha
        android:duration="90"
        android:fromAlpha="0.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1.0" />

</set>
dialog_scale_anim_out:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <scale
        android:duration="150"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0.6"
        android:toYScale="0.6" />

    <alpha
        android:duration="150"
        android:fromAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="0.0" /> 

</set>

dialog_test:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_view"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@color/comment_dialog_bg"
        android:orientation="vertical"
        android:padding="10.0dip">

        <EditText
            android:id="@+id/comment_editor"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/bg_detail_comment_editor"
            android:hint="@string/ss_share_hint"
            android:maxHeight="120.0dip"
            android:padding="9.0dip"
            android:textColor="@color/comment_dialog_content_text"
            android:textSize="16.0sp" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10.0dip"
            android:gravity="center_vertical">

            <TextView
                android:id="@+id/share_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginRight="10.0dip"
                android:text="@string/comment_dialog_share_label"
                android:textColor="@color/comment_dialog_share_text"
                android:textSize="13.0sp" />

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1">

                <ImageView
                    android:id="@+id/account_icon_weibo"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@drawable/account_icon_weibo" />

                <ImageView
                    android:id="@+id/account_icon_tencent"
                    android:layout_width="wrap_content"
                    android:layout_marginLeft="10dp"
                    android:layout_height="wrap_content"
                    android:src="@drawable/account_icon_tencent" />

            </LinearLayout>

            <LinearLayout
                android:id="@+id/platform_layout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@id/share_label"
                android:orientation="horizontal" />

            <TextView
                android:id="@+id/submit_btn"
                android:layout_width="50.0dip"
                android:layout_height="25.0dip"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:background="@drawable/bg_comment_submit"
                android:gravity="center"
                android:text="@string/comment_dialog_send"
                android:textColor="@color/comment_dialog_submit_text"
                android:textSize="13.0sp" />

            <TextView
                android:id="@+id/text_limit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginRight="10.0dip"
                android:layout_toLeftOf="@id/submit_btn"
                android:textSize="13.0sp"
                android:visibility="invisible" />
        </LinearLayout>
    </LinearLayout>
</FrameLayout>

使用很简单:

findViewById(R.id.ceshi).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
                .setContentView(R.layout.dialog_test)
                .fullWidth()
                .fromButtom(true)
                .show();
        dialog.setOnClickListener(R.id.send, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "点击了发送", Toast.LENGTH_SHORT).show();
            }
        });
    }
});

效果图如下:


Builder设计模式构建万能Dialog