Android 自定义View 之 Dialog弹窗

news2025/2/13 0:16:16

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

然后我们运行一下:

在这里插入图片描述

七、简易使用

  上面的代码的作用是为了让你能更好的设置弹窗的属性,而如果你想要很简单的使用,例如一行代码解决问题,也可以,为此我单独写了一个工具类在库里面,因为是使用的关系,所以就不贴代码了,你可以去源码中去看,那么当一个新的项目要使用这个弹窗需要怎么做呢?通过引入依赖的方式,例如在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);

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

在这里插入图片描述

八、源码

如果对你有所帮助的话,不妨 Star 或 Fork,山高水长,后会有期~

源码地址:EasyView

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/639696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux 内核版本和发行版本

当要明确自己的Linux系统的版本号时&#xff0c;大多数情况是用命令确定Linux内核版本的。不过这个还是要与CentOS的版本号&#xff08;就是你使用的Linux系统的发行版本&#xff09;区分开来&#xff0c;这两个不是一个东西。 一、发行版本号 比如当时安装CentOS时&#x…

【Python】集合 set ① ( 集合定义 | 集合特点 | 代码示例 - 集合定义 )

文章目录 一、集合特点二、集合定义三、代码示例 - 集合定义 一、集合特点 在之前 的博客中 介绍了 列表 / 元组 / 字符串 数据容器 , 列表 支持 定义后 , 增加元素 / 修改元素 / 删除元素 , 并且 列表中可以存储 重复 / 有序 的元素 ;元组 定义后 不能 进行 增加元素 / 修改元…

(转载)有导师学习神经网络的回归拟合(matlab实现)

神经网络的学习规则又称神经网络的训练算法&#xff0c;用来计算更新神经网络的权值和阈值。学习规则有两大类别&#xff1a;有导师学习和无导师学习。在有导师学习中&#xff0c;需要为学习规则提供一系列正确的网络输入/输出对(即训练样本),当网络输入时&#xff0c;将网络输…

对于Promise的理解

1.什么是回调地狱 多层异步函数的嵌套叫做回调地狱 代码1&#xff1a; setTimeout(() > {console.log(吃饭);setTimeout(() > {console.log(睡觉);setTimeout(() > {console.log(打豆豆);}, 1000);}, 2000);}, 3000); 代码2: 通过id获取用户名,通过用户名获取邮箱…

如何自动识别快递单号和批量查询的方法

最近有很多朋友问我&#xff0c;有没有办法批量查询快递单号&#xff0c;查询该快递单号的所有物流发货信息&#xff1f;今天小编就来分享一个实用的查询技巧&#xff0c;教大家轻松查询多个快递单号&#xff0c;还可以一键保存查询数据&#xff0c;一起来看看吧。 首先今天我们…

PoseNet深度网络进行6D位姿估计的训练,python3实现

0.相关github网址 原版github代码-caffe实现tensorflow实现&#xff0c;相关版本较低&#xff0c;python2&#xff0c;本文根据此代码迁移到python3上面。pytorch实现&#xff0c;但将骨干模型从goglenet改成了resnet&#xff0c;实验效果得到提升&#xff0c;但没公布预训练权…

快递单号一键批量查询的具体操作方法和步骤

最近做电商的朋友对一个话题很感兴趣&#xff1a;如何批量查询快递单号&#xff1f;今天&#xff0c;小编给你安利一款软件&#xff1a;固乔快递查询助手&#xff0c;支持大量快递单号的批量查询。下面我们来看看批量查询的具体操作方法。 小伙伴们需要先在“固乔科技”的官网上…

session与cookie的来源与区别

目录 1.什么是HTTP&#xff1f; 2.cookie 3.session 4.cookie和session的区别 如果你对于session 和cookie 只有一点模糊理解&#xff0c;那么此文章能帮你更深入理解session和cookie &#xff0c;依旧和上篇文章一样&#xff0c;我们采用问题的方式来一步步探索&#xff0…

第七章 测试

文章目录 第七章 测试7.1 编码7.1.1 选择程序设计语言1. 计算机程序设计语言基本上可以分为汇编语言和高级语言2. 从应用特点看&#xff0c;高级语言可分为基础语言、结构化语言、专用语言 7.1.2 编码风格 7.2 软件测试基础7.2.1 软件测试的目标7.2.2 软件测试准则7.2.3 测试方…

JVM基础面试题及原理讲解

基本问题 介绍下 Java 内存区域&#xff08;运行时数据区&#xff09;Java 对象的创建过程&#xff08;五步&#xff0c;建议能默写出来并且要知道每一步虚拟机做了什么&#xff09;对象的访问定位的两种方式&#xff08;句柄和直接指针两种方式&#xff09; 拓展问题 Strin…

Flutter Widget 生命周期 key探究

Widget 在Flutter中&#xff0c;一切皆是Widget&#xff08;组件&#xff09;&#xff0c;Widget的功能是“描述一个UI元素的配置数据”&#xff0c;它就是说&#xff0c;Widget其实并不是表示最终绘制在设备屏幕上的显示元素&#xff0c;它只是描述显示元素的一个配置数据。 …

分库分表 21 招

&#xff08;一&#xff09;好好的系统&#xff0c;为什么要分库分表&#xff1f; 咱们先介绍下在分库分表架构实施过程中&#xff0c;会接触到的一些通用概念&#xff0c;了解这些概念能够帮助理解市面上其他的分库分表工具&#xff0c;尽管它们的实现方法可能存在差异&#…

自动化测试框架seldom

创建项目 | seldom文档 这个框架还是不错的&#xff0c;一直在优化&#xff0c;测试框架里的功能这里都有了。 seldom继承unittest单元测试框架&#xff0c;可以用来做UI和接口自动化项目。 安装 pip install seldom 创建项目 > seldom -P mypro 创建测试用例 # tes…

第8章 维护

文章目录 第8章 维护一、软件交付使用的工作二、软件交付使用的方式1) 直接方式2) 并行方式3) 逐步方式 8.1 软件维护的定义1、软件维护的定义2、软件维护的原因3、软件维护的类型1、改正性维护2、适应性维护3、完善性维护4、预防性维护 8.2 软件维护的特点8.2.1结构化维护和非…

12.异常-Exception|Java学习笔记

文章目录 异常介绍异常体系图一览运行时异常编译异常异常处理异常处理的方式try-catch 异常处理throws 异常处理注意事项和使用细节 自定义异常自定义异常的步骤 throw和throws的区别 异常介绍 基本概念&#xff1a;Java语言中&#xff0c;将程序执行中发生的不正常情况称为“…

【TCP/IP】多进程服务器的实现(进阶) - 多进程服务器模型及代码实现

经过前面的铺垫&#xff0c;我们已经具备实现并发服务器的基础了&#xff0c;接下来让我们尝试将之前的单任务回声服务器改装成多任务并发模式吧&#xff01; 多任务回声服务器模型 在编写代码前&#xff0c;先让我们大致将多任务&#xff08;回声&#xff09;服务器的模型抽象…

mac下部署和访问 Kubernetes 仪表板(Dashboard)

简介 Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中&#xff0c;也可以对容器应用排错&#xff0c;还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息&#xff0c;也可以创建或者修改 Kub…

技术分享——隐私计算简介

随着数据规模的不断扩大和网络技术的快速发展&#xff0c;数据安全和隐私保护成为了热门的话题。隐私计算作为一种新兴的数据安全和隐私保护技术&#xff0c;为数据安全和隐私泄露问题提供了新的思路和方法。 2020年10月19日&#xff0c;Gartner发布2021年前沿战略科技趋势&am…

VTK源码编译安装记录与教程(VS2019+QT5.15.2+PCL1.12.1+VTK9.1.0配置,超详细)

因为PCL库&#xff08;傻瓜式安装&#xff09;中自动安装的VTK库并不完整&#xff0c;不支持QT环境的UI界面开发&#xff0c;于是&#xff0c;想用QT在VS2019上开发图形界面程序&#xff0c;需要单独自己通过VTK源码编译安装&#xff0c;再进行配置。本人安装时开发环境已经装好…

2023拒绝行业内卷!八年软件测试月薪30K*16薪行业心得 想入行必看

目前工作做软件测试工作8年&#xff0c;属于高级测试员那个级别吧&#xff01;现在看到各行各业的人都在转行学习软件测试&#xff0c;想给大家一些学习建议和忠告。 很多粉丝都跟我说今年行情很差&#xff0c;找不到工资&#xff0c;真的找不到工作了吗&#xff1f; 我们常在网…