我正在参加「启航计划」

前语

  在日常开发中用到弹窗是比较多的,常用于提示效果,比如错误操作提示,余额缺乏提示,退出登录提示等,还有用于数据展现的弹窗,上拉弹窗等等,首要为了简化在日常开发中的运用。

Android 自定义View 之 Dialog弹窗

正文

  Android中的Dialog弹窗是一种用于展现特定信息或许在用户需求进行某些操作时才显现的窗口。Dialog弹窗能够分为体系供给的惯例Dialog弹窗和自界说Dialog弹窗。

  惯例Dialog弹窗包括AlertDialog、ProgressDialog、DatePickerDialog、TimePickerDialog等,这些Dialog弹窗能够直接运用体系供给的API进行创立和运用。

一、弹窗视图协助类

  下面咱们来开端写代码,首要创立一个dialog包,然后在包下新建一个DialogViewHelper类,代码如下:

public class DialogViewHelper {
    //内容视图
    private final View mView;
    //弱运用视图
    private final SparseArray<WeakReference<View>> mSubViews;
    /**
     * 结构办法
     *
     * @param view 视图
     */
    public DialogViewHelper(View view) {
        //初始化
        mSubViews = new SparseArray<>();
        //获取弹窗视图
        mView = view;
    }
    /**
     * 结构办法
     *
     * @param context     上下文
     * @param layoutResId 布局资源id
     */
    public DialogViewHelper(Context context, int layoutResId) {
        //初始化
        mSubViews = new SparseArray<>();
        //获取弹窗视图
        mView = LayoutInflater.from(context).inflate(layoutResId, null);
    }
    /**
     * 获取弹窗内容视图
     *
     * @return mView
     */
    public View getContentView() {
        return mView;
    }
    /**
     * 获取子视图
     *
     * @param viewId 视图id
     * @return view
     */
    public View getSubView(int viewId) {
        //经过视图id得到弱引证视图
        WeakReference<View> viewWeakReference = mSubViews.get(viewId);
        View view = null;
        //假如弱引证视图不为空,阐明有对应的xml文件,则对view进行赋值
        if (viewWeakReference != null) {
            view = viewWeakReference.get();
        }
        //假如view为空,则阐明上面的弱引证列表数据不存在,经过findViewById办法从头赋值,不为空再放到数组
        if (view == null) {
            view = mView.findViewById(viewId);
            if (view != null) {
                mSubViews.put(viewId, new WeakReference<>(view));
            }
        }
        return view;
    }
    /**
     * 设置文本
     *
     * @param viewId 视图id
     * @param text   字符
     */
    public void setText(int viewId, CharSequence text) {
        TextView tv = (TextView) getSubView(viewId);
        if (tv != null) {
            tv.setText(text);
        }
    }
    /**
     * 设置文本
     *
     * @param viewId 视图id
     * @param color  色彩
     */
    public void setTextColor(int viewId, int color) {
        TextView tv = (TextView) getSubView(viewId);
        if (tv != null) {
            tv.setTextColor(color);
        }
    }
    /**
     * 设置图标
     *
     * @param viewId 视图id
     * @param icon   图标
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    public void setImageIcon(int viewId, Icon icon) {
        ImageView iv = (ImageView) getSubView(viewId);
        if (iv != null) {
            iv.setImageIcon(icon);
        }
    }
    /**
     * 设置图片
     *
     * @param viewId 视图id
     * @param resId  图标资源id
     */
    public void setImageResource(int viewId, int resId) {
        ImageView iv = (ImageView) getSubView(viewId);
        if (iv != null) {
            iv.setImageResource(resId);
        }
    }
    /**
     * 设置图片
     *
     * @param viewId   视图id
     * @param drawable 图
     */
    public void setImageDrawable(int viewId, Drawable drawable) {
        ImageView iv = (ImageView) getSubView(viewId);
        if (iv != null) {
            iv.setImageDrawable(drawable);
        }
    }
    /**
     * 设置图片
     *
     * @param viewId 视图id
     * @param bitmap 图片
     */
    public void setImageBitmap(int viewId, Bitmap bitmap) {
        ImageView iv = (ImageView) getSubView(viewId);
        if (iv != null) {
            iv.setImageBitmap(bitmap);
        }
    }
    /**
     * 设置布景色彩
     *
     * @param viewId 视图id
     * @param color  色彩
     */
    public void setBackgroundColor(int viewId, int color) {
        View view = getSubView(viewId);
        if (view != null) {
            view.setBackgroundColor(color);
        }
    }
    /**
     * 设置布景
     *
     * @param viewId   视图id
     * @param drawable drawable
     */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void setBackground(int viewId, Drawable drawable) {
        View view = getSubView(viewId);
        if (view != null) {
            view.setBackground(drawable);
        }
    }
    /**
     * 设置点击监听
     *
     * @param viewId          视图id
     * @param onClickListener 点击监听
     */
    public void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        View view = getSubView(viewId);
        if (view != null) {
            view.setOnClickListener(onClickListener);
        }
    }
}

  这个弹窗视图协助类,经过结构办法界说参数的办法,在运用的时分能够传递弹窗视图Id也能够直接传View进来,这是获取弹窗的视图,还有获取弹窗视图中的子控件的视图,经过获取子控件的视图就能够对子控件如TextView、ImageView、View等控件进行特点及点击事情的设置。

二、弹窗操控类

  上面写好了弹窗协助类,下面写操控类,会用到上面的协助类,咱们来看看是怎样用的,在dialog下创立EasyDialog类,先写一个空的类就好了,代码如下:

public class EasyDialog extends Dialog {
}

这里咱们承继自Dialog,下面咱们创立DialogController,这是咱们的调用的类,代码如下所示:

public class DialogController {
    //对话弹窗
    private final EasyDialog mEasyDialog;
    //窗口
    private final Window mWindow;
    //协助类
    private DialogViewHelper mViewHelper;
    public DialogController(EasyDialog easyDialog, Window window) {
        mEasyDialog = easyDialog;
        mWindow = window;
    }
    public void setDialogViewHelper(DialogViewHelper dialogViewHelper) {
        mViewHelper = dialogViewHelper;
    }
    public void setText(int viewId, CharSequence text) {
        mViewHelper.setText(viewId, text);
    }
    public void setTextColor(int viewId, int color) {
        mViewHelper.setTextColor(viewId, color);
    }
    @RequiresApi(api = Build.VERSION_CODES.M)
    public void setImageIcon(int viewId, Icon icon) {
        mViewHelper.setImageIcon(viewId, icon);
    }
    public void setImageBitmap(int viewId, Bitmap bitmap) {
        mViewHelper.setImageBitmap(viewId, bitmap);
    }
    public void setImageDrawable(int viewId, Drawable drawable) {
        mViewHelper.setImageDrawable(viewId, drawable);
    }
    public void setImageResource(int viewId, int resId) {
        mViewHelper.setImageResource(viewId, resId);
    }
    public View getView(int viewId) {
        return mViewHelper.getSubView(viewId);
    }
    public void setBackgroundColor(int viewId, int color) {
        mViewHelper.setBackgroundColor(viewId, color);
    }
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void setBackground(int viewId, Drawable drawable) {
        mViewHelper.setBackground(viewId, drawable);
    }
    public void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        mViewHelper.setOnClickListener(viewId, onClickListener);
    }
    public EasyDialog getDialog() {
        return mEasyDialog;
    }
    public Window getWindow() {
        return mWindow;
    }
    /**
     * 弹窗参数类
     */
    @SuppressLint("UseSparseArrays")
    public static class DialogParams {
        //上下文
        public Context mContext;
        //主题资源Id
        public int mThemeResId;
        //点击其他区域弹窗是否撤销
        public boolean mCancelable;
        //弹窗撤销监听
        public DialogInterface.OnCancelListener mOnCancelListener;
        //弹窗躲藏监听
        public DialogInterface.OnDismissListener mOnDismissListener;
        //键值监听
        public DialogInterface.OnKeyListener mOnKeyListener;
        //文本色彩
        public SparseArray<Integer> mTextColorArray = new SparseArray<>();
        //布景色彩
        public SparseArray<Integer> mBgColorArray = new SparseArray<>();
        //布景资源
        public SparseArray<Drawable> mBgResArray = new SparseArray<>();
        //寄存文本
        public SparseArray<CharSequence> mTextArray = new SparseArray<>();
        //寄存点击事情
        public SparseArray<View.OnClickListener> mClickArray = new SparseArray<>();
        //寄存长按点击事情
        public SparseArray<View.OnLongClickListener> mLongClickArray = new SparseArray<>();
        //寄存对话框图标
        public SparseArray<Icon> mIconArray = new SparseArray<>();
        //寄存对话框图片
        public SparseArray<Bitmap> mBitmapArray = new SparseArray<>();
        //寄存对话框图片
        public SparseArray<Drawable> mDrawableArray = new SparseArray<>();
        //寄存对话框图标资源文件
        public SparseArray<Integer> mImageResArray = new SparseArray<>();
        //对话框布局资源id
        public int mLayoutResId;
        //对话框的内容view
        public View mView;
        //对话框宽度
        public int mWidth;
        //对话框高度
        public int mHeight;
        //对话框垂直外边距
        public int mHeightMargin;
        //对话框横向外边距
        public int mWidthMargin;
        //对话框呈现动画
        public int mAnimation;
        //对话框显现方位,默许居中显现
        public int mGravity = Gravity.CENTER;
        public DialogParams(Context context, int themeResId) {
            mContext = context;
            mThemeResId = themeResId;
        }
        /**
         * 运用
         */
        public void apply(DialogController controller) {
            DialogViewHelper helper = null;
            if (mView != null) {
                helper = new DialogViewHelper(mView);
            } else if (mLayoutResId != 0) {
                helper = new DialogViewHelper(mContext, mLayoutResId);
            }
            //假如helper为null,则mLayoutResId为0,没有设置弹窗xml
            if (helper == null) {
                throw new IllegalArgumentException("Please set layout!");
            }
            //为对话框设置内容视图
            controller.getDialog().setContentView(helper.getContentView());
            //设置DialogViewHelper辅助类
            controller.setDialogViewHelper(helper);
            //设置文本
            for (int i = 0; i < mTextArray.size(); i++) {
                controller.setText(mTextArray.keyAt(i), mTextArray.valueAt(i));
            }
            //设置文本色彩
            for (int i = 0; i < mTextColorArray.size(); i++) {
                controller.setTextColor(mTextColorArray.keyAt(i), mTextColorArray.valueAt(i));
            }
            //设置图标
            for (int i = 0; i < mIconArray.size(); i++) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    controller.setImageIcon(mIconArray.keyAt(i), mIconArray.valueAt(i));
                }
            }
            //设置图片
            for (int i = 0; i < mBitmapArray.size(); i++) {
                controller.setImageBitmap(mBitmapArray.keyAt(i), mBitmapArray.valueAt(i));
            }
            //设置图片
            for (int i = 0; i < mDrawableArray.size(); i++) {
                controller.setImageDrawable(mDrawableArray.keyAt(i), mDrawableArray.valueAt(i));
            }
            //设置图片
            for (int i = 0; i < mImageResArray.size(); i++) {
                controller.setImageResource(mImageResArray.keyAt(i), mImageResArray.valueAt(i));
            }
            //设置布景色彩
            for (int i = 0; i < mBgColorArray.size(); i++) {
                controller.setBackgroundColor(mBgColorArray.keyAt(i), mBgColorArray.valueAt(i));
            }
            //设置布景资源
            for (int i = 0; i < mBgResArray.size(); i++) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    controller.setBackground(mBgResArray.keyAt(i), mBgResArray.valueAt(i));
                }
            }
            //设置点击
            for (int i = 0; i < mClickArray.size(); i++) {
                controller.setOnClickListener(mClickArray.keyAt(i), mClickArray.valueAt(i));
            }
            //配置自界说效果,底部弹出,宽高,动画,全屏
            Window window = controller.getWindow();
            //显现方位
            window.setGravity(mGravity);
            if (mAnimation != 0) {
                //设置动画
                window.setWindowAnimations(mAnimation);
            }
            //设置布局参数,首要是宽高和边距
            WindowManager.LayoutParams params = window.getAttributes();
            params.width = mWidth;
            params.height = mHeight;
            params.verticalMargin = mHeightMargin;
            params.horizontalMargin = mWidthMargin;
            window.setAttributes(params);
        }
    }
}

  这个操控类分为两个部分,一部分是用来设置弹窗协助类的特点,一部分是界说弹窗的参数,DialogController中的办法直接调用DialogViewHelper的办法。然后是DialogParams类,里面界说了弹窗的一些参数,有一个结构办法,传入上下文和主题,然后经过apply()办法去设置DialogController中的办法,最终设置弹窗的方位和动画效果以及宽高。

三、监听接口

  一般的提示窗都有两个按钮,确认和撤销,咱们能够经过接口去进行运用,在dialog包下新建一个listener包,包下新建一个OnConfirmListener接口,代码如下:

public interface OnConfirmListener {
    void onConfirm();
}

再创立一个OnCancelListener接口,代码如下:

public interface OnCancelListener {
    void onCancel();
}

当然你还能够创立一个弹窗消失的监听接口。

四、款式

  为了增加用户体验,咱们能够为弹窗增加呈现和消失的动画效果,下面在themes.xml中增加如下代码:

    <!--自界说对话框-->
    <style name="EasyDialog" parent="@android:style/Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:windowNoTitle">true</item>
    </style>

这是弹窗的款式,下面咱们界说弹窗呈现和消失的动画,在res下新建一个anim包,以下的xml文件都在这个包下,创立dialog_scale_anim_in.xml,代码如下所示:

<?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,代码如下:

<?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_from_top_anim_in.xml,代码如下所示:

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

dialog_from_top_anim_out.xml,代码如下所示:

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

dialog_from_right_anim_in.xml,代码如下所示:

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

dialog_from_right_anim_out.xml,代码如下所示:

<?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:toXDelta="1000"
        android:toYDelta="0" />
</set>

dialog_from_bottom_anim_in.xml,代码如下所示:

<?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="1000"
        android:toXDelta="0"
        android:toYDelta="0" />
</set>

dialog_from_bottom_anim_out.xml,代码如下所示:

<?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:toXDelta="0"
        android:toYDelta="100%" />
</set>

dialog_from_left_anim_in.xml,代码如下所示:

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

dialog_from_left_anim_out.xml,代码如下所示:

<?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:toXDelta="-100%"
        android:toYDelta="0" />
</set>

现在款式和动画都写好了,下面能够去写EasyDialog中的代码了。

五、简易弹窗

  在上面咱们现已创立了EasyDialog,下面修正EasyDialog,代码如下所示:

public class EasyDialog extends Dialog {
    private final DialogController mController;
    public EasyDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
        mController = new DialogController(this, getWindow());
    }
    public void setText(int viewId, CharSequence text) {
        mController.setText(viewId, text);
    }
    public View getView(int viewId) {
        return mController.getView(viewId);
    }
    public void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        mController.setOnClickListener(viewId, onClickListener);
    }
    /**
     * EasyDialog 构建器
     */
    public static class Builder {
        //弹窗参数类
        private final DialogController.DialogParams dialogParams;
        public Builder(Context context) {
            this(context, R.style.EasyDialog);
        }
        public Builder(Context context, int themeResId) {
            dialogParams = new DialogController.DialogParams(context, themeResId);
        }
        /**
         * 设置对话框内容视图
         *
         * @param view 视图
         * @return Builder
         */
        public Builder setContentView(View view) {
            dialogParams.mView = view;
            dialogParams.mLayoutResId = 0;
            return this;
        }
        /**
         * 设置对话框内容视图
         *
         * @param layoutId 布局id
         * @return Builder
         */
        public Builder setContentView(int layoutId) {
            dialogParams.mView = null;
            dialogParams.mLayoutResId = layoutId;
            return this;
        }
        /**
         * 设置文本
         *
         * @param viewId 视图id
         * @param text   字符内容
         * @return Builder
         */
        public Builder setText(int viewId, CharSequence text) {
            dialogParams.mTextArray.put(viewId, text);
            return this;
        }
        /**
         * 设置文本色彩
         *
         * @param viewId 视图id
         * @param color  文字色彩
         * @return Builder
         */
        public Builder setTextColor(int viewId, int color) {
            dialogParams.mTextColorArray.put(viewId, color);
            return this;
        }
        /**
         * 设置布景
         *
         * @param viewId   视图id
         * @param drawable 资源
         * @return Builder
         */
        public Builder setBackground(int viewId, Drawable drawable) {
            dialogParams.mBgResArray.put(viewId, drawable);
            return this;
        }
        /**
         * 设置布景色彩
         *
         * @param viewId 视图id
         * @param color  色彩
         * @return Builder
         */
        public Builder setBackgroundColor(int viewId, int color) {
            dialogParams.mBgColorArray.put(viewId, color);
            return this;
        }
        /**
         * 设置图标
         *
         * @param viewId 视图id
         * @return Builder
         */
        public Builder setIcon(int viewId, Icon icon) {
            dialogParams.mIconArray.put(viewId, icon);
            return this;
        }
        /**
         * 设置图片
         *
         * @param viewId 视图id
         * @param bitmap 位图
         * @return Builder
         */
        public Builder setBitmap(int viewId, Bitmap bitmap) {
            dialogParams.mBitmapArray.put(viewId, bitmap);
            return this;
        }
        /**
         * 设置图片
         *
         * @param viewId   视图id
         * @param drawable 图片
         * @return Builder
         */
        public Builder setDrawable(int viewId, Drawable drawable) {
            dialogParams.mDrawableArray.put(viewId, drawable);
            return this;
        }
        /**
         * 设置图片
         *
         * @param viewId 视图id
         * @param resId  图片资源id
         * @return Builder
         */
        public Builder setImageRes(int viewId, int resId) {
            dialogParams.mImageResArray.put(viewId, resId);
            return this;
        }
        /**
         * 设置对话框宽度占满屏幕
         *
         * @return Builder
         */
        public Builder fullWidth() {
            dialogParams.mWidth = ViewGroup.LayoutParams.MATCH_PARENT;
            return this;
        }
        /**
         * 设置对话框高度占满屏幕
         *
         * @return Builder
         */
        public Builder fullHeight() {
            dialogParams.mHeight = ViewGroup.LayoutParams.MATCH_PARENT;
            return this;
        }
        /**
         * 设置对话框宽高
         *
         * @param width  宽
         * @param height 高
         * @return Builder
         */
        public Builder setWidthAndHeight(int width, int height) {
            dialogParams.mWidth = width;
            dialogParams.mHeight = height;
            return this;
        }
        /**
         * 设置对话框宽高和宽高边距
         *
         * @param width        宽
         * @param height       高
         * @param widthMargin  宽边距
         * @param heightMargin 高边距
         * @return Builder
         */
        public Builder setWidthAndHeightMargin(int width, int height, int widthMargin, int heightMargin) {
            dialogParams.mWidth = width;
            dialogParams.mHeight = height;
            dialogParams.mWidthMargin = widthMargin;
            dialogParams.mHeightMargin = heightMargin;
            return this;
        }
        /**
         * 设置动画
         *
         * @param styleAnimation 对话框动画
         * @return Builder
         */
        public Builder setAnimation(int styleAnimation) {
            dialogParams.mAnimation = styleAnimation;
            return this;
        }
        /**
         * 增加默许动画
         *
         * @return Builder
         */
        public Builder addDefaultAnimation() {
            dialogParams.mAnimation = R.style.dialog_scale_anim;
            return this;
        }
        /**
         * 增加自界说动画
         * @param gravity 弹窗方位  联系到运用什么动画
         * @param isAnimation 是否敞开动画
         * @return Builder
         */
        public Builder addCustomAnimation(int gravity, boolean isAnimation) {
            switch (gravity) {
                case Gravity.TOP:
                    dialogParams.mGravity = Gravity.TOP;
                    dialogParams.mAnimation = R.style.dialog_from_top_anim;
                    break;
                case Gravity.RIGHT:
                    dialogParams.mGravity = Gravity.RIGHT;
                    dialogParams.mAnimation = R.style.dialog_from_right_anim;
                    break;
                case Gravity.BOTTOM:
                    dialogParams.mGravity = Gravity.BOTTOM;
                    dialogParams.mAnimation = R.style.dialog_from_bottom_anim;
                    break;
                case Gravity.LEFT:
                    dialogParams.mGravity = Gravity.LEFT;
                    dialogParams.mAnimation = R.style.dialog_from_left_anim;
                    break;
                default:
                    dialogParams.mGravity = Gravity.CENTER;
                    dialogParams.mAnimation = R.style.dialog_scale_anim;
                    break;
            }
            if (!isAnimation) {
                dialogParams.mAnimation = 0;
            }
            return this;
        }
        /**
         * 设置对话框是否可撤销,默许为true。
         *
         * @return Builder
         */
        public Builder setCancelable(boolean cancelable) {
            dialogParams.mCancelable = cancelable;
            return this;
        }
        /**
         * 设置点击事情监听
         *
         * @param viewId          视图id
         * @param onClickListener 点击事情
         * @return Builder
         */
        public Builder setOnClickListener(int viewId, View.OnClickListener onClickListener) {
            dialogParams.mClickArray.put(viewId, onClickListener);
            return this;
        }
        /**
         * 设置长按事情监听
         *
         * @param viewId              视图id
         * @param onLongClickListener 长按事情
         * @return Builder
         */
        public Builder setOnLongClickListener(int viewId, View.OnLongClickListener onLongClickListener) {
            dialogParams.mLongClickArray.put(viewId, onLongClickListener);
            return this;
        }
        /**
         * 设置撤销事情监听
         *
         * @param onCancelListener 撤销事情监听
         * @return Builder
         */
        public Builder setOnCancelListener(OnCancelListener onCancelListener) {
            dialogParams.mOnCancelListener = onCancelListener;
            return this;
        }
        /**
         * 设置躲藏事情监听
         *
         * @param onDismissListener 躲藏事情监听
         * @return Builder
         */
        public Builder setOnDismissListener(OnDismissListener onDismissListener) {
            dialogParams.mOnDismissListener = onDismissListener;
            return this;
        }
        /**
         * 设置键监听
         *
         * @param onKeyListener 键监听事情
         * @return Builder
         */
        public Builder setOnKeyListener(OnKeyListener onKeyListener) {
            dialogParams.mOnKeyListener = onKeyListener;
            return this;
        }
        /**
         * 创立弹窗
         *
         * @return EasyDialog
         */
        public EasyDialog create() {
            //经过上下文和主题款式设置弹窗
            final EasyDialog dialog = new EasyDialog(dialogParams.mContext, dialogParams.mThemeResId);
            //运用弹窗操控器
            dialogParams.apply(dialog.mController);
            //设置对话框是否可撤销
            dialog.setCancelable(dialogParams.mCancelable);
            if (dialogParams.mCancelable) {
                //设置撤销在触摸外面
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(dialogParams.mOnCancelListener);
            dialog.setOnDismissListener(dialogParams.mOnDismissListener);
            if (dialogParams.mOnKeyListener != null) {
                dialog.setOnKeyListener(dialogParams.mOnKeyListener);
            }
            return dialog;
        }
        /**
         * 显现弹窗
         *
         * @return dialog
         */
        public EasyDialog show() {
            final EasyDialog dialog = create();
            dialog.show();
            return dialog;
        }
    }
}

  这里面的中心是Builder类,经过链式调用咱们能够自在的为EasyDialog设置需求的特点,然后就是对里面的各个办法进行处理,相信你看到代码就知道是什么意思了,况且还有注释,到这里停止其实咱们的弹窗就现已写好了,下面我将阐明一下怎样运用它。

六、惯例运用

  下面咱们在Activity中运用它,修正xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".used.EasyDialogActivity">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="----------------- 惯例运用 -----------------"
        android:textColor="@color/black" />
    <LinearLayout
        android:gravity="center_vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView
            android:text="呈现方位:"
            android:textColor="@color/black"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
        <RadioGroup
            android:id="@+id/rg_gravity"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <RadioButton
                android:id="@+id/rb_top"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="上" />
            <RadioButton
                android:id="@+id/rb_right"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="右" />
            <RadioButton
                android:id="@+id/rb_bottom"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下" />
            <RadioButton
                android:id="@+id/rb_left"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="左" />
            <RadioButton
                android:id="@+id/rb_center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="中" />
        </RadioGroup>
    </LinearLayout>
    <CheckBox
        android:id="@+id/cb_animation"
        android:text="是否需求动画"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <CheckBox
        android:id="@+id/cb_cancelable"
        android:text="是否点击外部消失"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/btn_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显现弹窗" />
</LinearLayout>

然后咱们在layout下创立一个dialog_warm_tip.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="300dp"
    android:layout_height="wrap_content"
    android:background="@drawable/shape_dialog_bg">
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:gravity="center"
        android:text="弹窗标题"
        android:textColor="@color/black"
        android:textSize="16sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <View
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/line"
        app:layout_constraintTop_toBottomOf="@+id/tv_title" />
    <TextView
        android:id="@+id/tv_content"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:gravity="center"
        android:text="你想要写什么内容呢?"
        android:textColor="@color/black"
        android:textSize="14sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view" />
    <View
        android:id="@+id/view_1"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/line"
        app:layout_constraintTop_toBottomOf="@+id/tv_content" />
    <TextView
        android:id="@+id/tv_cancel"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:gravity="center"
        android:text="撤销"
        android:textColor="@color/black"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/view_2"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view_1" />
    <View
        android:id="@+id/view_2"
        android:layout_width="1dp"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/line"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/tv_confirm"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/tv_cancel"
        app:layout_constraintTop_toBottomOf="@+id/view_1" />
    <TextView
        android:id="@+id/tv_confirm"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:gravity="center"
        android:text="确认"
        android:textColor="@color/black"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/view_2"
        app:layout_constraintTop_toBottomOf="@+id/view_1" />
</androidx.constraintlayout.widget.ConstraintLayout>

下面修正一下Activity中的代码,如下所示:

public class EasyDialogActivity extends EasyActivity<ActivityEasyDialogBinding> implements View.OnClickListener, CompoundButton.OnCheckedChangeListener, RadioGroup.OnCheckedChangeListener {
    private EasyDialog easyDialog;
    private EasyDialog.Builder builder;
    private int mGravity;
    private boolean mIsAnimation;
    private boolean mIsCancelable;
    @Override
    protected void onCreate() {
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        builder = new EasyDialog.Builder(EasyDialogActivity.this);
        initView();
    }
    private void initView() {
        binding.btnShow.setOnClickListener(this);
        binding.rgGravity.setOnCheckedChangeListener(this);
        binding.cbAnimation.setOnCheckedChangeListener(this);
        binding.cbCancelable.setOnCheckedChangeListener(this);
    }
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        if (builder != null) {
            switch (checkedId) {
                case R.id.rb_top:
                    mGravity = Gravity.TOP;
                    break;
                case R.id.rb_right:
                    mGravity = Gravity.RIGHT;
                    break;
                case R.id.rb_bottom:
                    mGravity = Gravity.BOTTOM;
                    break;
                case R.id.rb_left:
                    mGravity = Gravity.LEFT;
                    break;
                case R.id.rb_center:
                    mGravity = Gravity.CENTER;
                    break;
            }
        }
    }
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (builder != null) {
            switch (buttonView.getId()) {
                case R.id.cb_animation:
                    mIsAnimation = isChecked;
                    break;
                case R.id.cb_cancelable:
                    mIsCancelable = isChecked;
                    break;
            }
        }
    }
    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_show:
                showDialog();
                break;
        }
    }
    /**
     * 显现弹窗
     */
    private void showDialog() {
        builder.setContentView(R.layout.dialog_warm_tip)
                //增加自界说动画
                .addCustomAnimation(mGravity, mIsAnimation)
                //设置对话框可撤销
                .setCancelable(mIsCancelable)
                //设置标题
                .setText(R.id.tv_title, "温馨提示")
                //设置内容
                .setText(R.id.tv_content, "您今天还没有搞钱,请记得搞钱!")
                //设置文字色彩
                .setTextColor(R.id.tv_confirm, ContextCompat.getColor(EasyDialogActivity.this, R.color.white))
                //设置布景资源
                .setBackground(R.id.tv_confirm, ContextCompat.getDrawable(EasyDialogActivity.this, R.drawable.shape_confirm_bg))
                //设置弹窗宽高
                .setWidthAndHeight(EasyUtils.dp2px(EasyDialogActivity.this, 320), LinearLayout.LayoutParams.WRAP_CONTENT)
                //增加点击事情  撤销
                .setOnClickListener(R.id.tv_cancel, v1 -> {
                    easyDialog.dismiss();
                })
                //增加点击事情  确认
                .setOnClickListener(R.id.tv_confirm, v2 -> {
                    showMsg("我知道了!");
                    easyDialog.dismiss();
                })
                //增加撤销监听
                .setOnCancelListener(dialog -> {
                    showMsg("弹窗撤销了");
                })
                //弹窗消失监听
                .setOnDismissListener(dialog -> {
                    showMsg("弹窗消失了");
                });
        //创立弹窗
        easyDialog = builder.create();
        //显现弹窗
        easyDialog.show();
    }
}

然后咱们运转一下:

Android 自定义View 之 Dialog弹窗

七、简易运用

  上面的代码的效果是为了让你能更好的设置弹窗的特点,而假如你想要很简单的运用,例如一行代码解决问题,也能够,为此我独自写了一个工具类在库里面,因为是运用的联系,所以就不贴代码了,你能够去源码中去看,那么当一个新的项目要运用这个弹窗需求怎样做呢?经过引入依靠的办法,例如在app模块中运用,则打开app模块下的build.gradle,在dependencies{}闭包下增加即可,之后记得要Sync Now

dependencies {
    implementation 'io.github.lilongweidev:easyview:1.0.5'
}

  然后运用,例如显现提示弹窗:

EasyDialogUtils.showTipDialog(EasyDialogActivity.this, "温馨提示", "端午又要调休!",
                        () -> showMsg("撤销"), () -> showMsg("确认"));

显现String列表挑选弹窗:

final String[] stringArr = {"富足", "民主", "文明", "调和", "自在", "相等", "公正", "法治", "爱国", "敬业", "诚信", "友善"};
List<String> stringList = new ArrayList<>(Arrays.asList(stringArr));
EasyDialogUtils.showSelectDialog(EasyDialogActivity.this, "社会主义中心价值观",
                        stringList, this::showMsg);

这样运用是不是很简单呢?

Android 自定义View 之 Dialog弹窗

八、源码

假如对你有所协助的话,无妨 Star 或 Fork,天长地久,后会有期~

源码地址:EasyView