Android 简单封装Toast工具类

作者: Gxinyu | 来源:发表于2019-04-13 16:49 被阅读61次

    今天在此分享一个之前自己封装的Toast工具类。作为一个提示类的组件,系统有些方面做得并不是特别好,比如多次点击会像冒泡一样显示,很多时候基本都是想让它显示一次而已。还有由于国内手机厂商对Rom层做的修改,出现很多不同形式的Toast,因此希望Toast在不同手机显示的形式一致, 并且不出现重复现象(例如:今日头条的Toast),所以有必要做一些简单的封装。还有一点市面上有关于修改Toast显示时长的,个人并不建议通过反射去修改toast的显示时长,既然Google只设置两种显示时长(Toast.LENGTH_SHORT和Toast.LENGTH_LONG),必定有合理性,Toast只是作为提醒功能使用,源码里面去除touch事件,如果项目中Toast满足不了,完全可以使用其他组件代替(Dialog等)。本工具类使用建造者模式构造,链式调用方便使用。

    简单使用

    Toastkeeper.getInstance()
       .createBuilder(this)
       .setMessage(message)
       .show();
    

    构造

    构造方法采用静态内部类方式

        //私有构造
        private Toastkeeper() {
        }
    
        private static class SingleTonHoler {
            private static Toastkeeper INSTANCE = new Toastkeeper();
        }
    
        public static Toastkeeper getInstance() {
            return SingleTonHoler.INSTANCE;
        }
    

    属性介绍

            //文本
            private CharSequence mMessage;
            //其他属性参数
            private int mDuration = DURATION_LONG;
            private int mGravity = GRAVITY_CENTER;
            private int mOffsetX = 0;
            private int mOffsetY = 0;
            private boolean mUseSystem = false;
            private boolean mCancleSame = true;
            private View mToastView = null;
            private @LayoutRes
            int mlayoutId = 0;
    
    • mMessage: 设置提醒的内容
    • mGravity、mOffsetX mOffsetY 用于定位
    • mUseSystem :是否使用系统的toast
    • mCancleSame :取消同一时间相同内容的toast
    • mToastView 和mlayoutId :用于自定义toast的view

    子线程处理:

    //构造
            final Context appContext = context.getApplicationContext();
            //兼容在子线程中显示
            if (isMainLooper()) {
                showToastSafety(appContext, builder);
            } else {
                sMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        showToastSafety(appContext, builder);
                    }
                });
            }
    

    说明:
    isMainLooper()用于判断当前线程是否是子线程

    去除相同的消息

    /**
         * 处理相同消息的tag
         * 如果使用系统toast的话,只比较Message,
         * 如果使用自定义的,则比较bean
         * 再次就是需要比较是否主动取消相同的消息
         *
         * @param builder
         * @return
         */
        private boolean handleSameToast(Builder builder) {
            boolean sameBuilder = false;
            boolean mCancleSame = builder.mCancleSame;
            boolean mUseSystem = builder.mUseSystem;
    
            if (mUseSystem) {
                sameBuilder = lastBuilder.mMessage.equals(builder.mMessage);
            } else {
                String lastBuilderS = lastBuilder.toString();
                String currentBuilderS = builder.toString();
                sameBuilder = lastBuilderS.equals(currentBuilderS);
            }
    
            return mCancleSame && sameBuilder;
        }
    

    后记

    由于只是做简单的封装,只需要一个单独的类,注释很明确,如遇到使用问题或者显示出错,记得及时反馈。所有代码直接贴在下面:

    /**
     * @author gexinyu
     */
    public class Toastkeeper  {
    
        //默认位置5种位置(注解方式限定设置的位置)
        public static final int GRAVITY_CENTER = Gravity.CENTER;
        public static final int GRAVITY_TOP = Gravity.TOP;
        public static final int GRAVITY_BOTTOM = Gravity.BOTTOM;
        public static final int GRAVITY_LEFT = Gravity.LEFT;
        public static final int GRAVITY_RIGHT = Gravity.RIGHT;
        //默认的两种toast显示时长
        public static final int DURATION_SHORT = Toast.LENGTH_SHORT;
        public static final int DURATION_LONG = Toast.LENGTH_LONG;
    
        @IntDef({DURATION_SHORT, DURATION_LONG})
        @Retention(RetentionPolicy.SOURCE)
        public @interface Duration {
        }
    
        @IntDef({GRAVITY_CENTER, GRAVITY_TOP, GRAVITY_BOTTOM, GRAVITY_LEFT, GRAVITY_RIGHT})
        @Retention(RetentionPolicy.SOURCE)
        public @interface IGravity {
        }
    
        //只有一个toast
        private Toast mToast;
        private boolean isShowing = false;
        //默认的view
        private TextView normalTextView = null;
        private Builder lastBuilder = null;
        //主线程的handle
        private Handler sMainHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                isShowing = false;
            }
        };
    
        //私有构造
        private Toastkeeper() {
        }
    
        private static class SingleTonHoler {
            private static Toastkeeper INSTANCE = new Toastkeeper();
        }
    
        public static Toastkeeper getInstance() {
            return SingleTonHoler.INSTANCE;
        }
    
        /**
         * 是否是主线程
         *
         * @return
         */
        private boolean isMainLooper() {
            return Looper.getMainLooper() == Looper.myLooper();
        }
    
        /**
         * 显示toast
         *
         * @param context
         * @param builder
         * @return
         */
        private void showToast(Context context, final Builder builder) {
            if (null == context) {
                throw new NullPointerException("you set context is null!");
            }
    
            if (null == builder) {
                throw new NullPointerException("you set builder is null!");
            }
            final Context appContext = context.getApplicationContext();
            //兼容在子线程中显示
            if (isMainLooper()) {
                showToastSafety(appContext, builder);
            } else {
                sMainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        showToastSafety(appContext, builder);
                    }
                });
            }
        }
    
    
        /**
         * 取消toast
         */
        private void dimissToast() {
            if (mToast != null) {
                mToast.cancel();
                isShowing = false;
            }
        }
    
        /**
         * 创建构造
         *
         * @param context
         * @return
         */
        public Builder createBuilder(Context context) {
            Builder builder = new Builder(context);
            return builder;
        }
    
        //*****************************构造builder***********************
    
        public final class Builder {
    
            private Context mContext;
            //文本
            private CharSequence mMessage;
            //其他属性参数
            private int mDuration = DURATION_LONG;
            private int mGravity = GRAVITY_CENTER;
            private int mOffsetX = 0;
            private int mOffsetY = 0;
            private boolean mUseSystem = false;
            private boolean mCancleSame = true;
            private View mToastView = null;
            private @LayoutRes
            int mlayoutId = 0;
    
            Builder(Context context) {
                mContext = context;
            }
    
            /**
             * 设置信息
             *
             * @param text
             * @return
             */
            public Builder setMessage(String text) {
                mMessage = text;
                return this;
            }
    
            /**
             * 设置时长
             *
             * @param duration
             * @return
             */
            public Builder setDuration(@Duration int duration) {
                mDuration = duration;
                return this;
            }
    
            /**
             * 设置位置
             *
             * @param gravity
             * @return
             */
            public Builder setGravity(@IGravity int gravity) {
                mGravity = gravity;
                return this;
            }
    
            /**
             * 设置X偏移
             *
             * @param offsetX
             * @return
             */
            public Builder setOffsetX(int offsetX) {
                mOffsetX = offsetX;
                return this;
            }
    
            /**
             * 设置Y偏移
             *
             * @param offsetY
             * @return
             */
            public Builder setOffsetY(int offsetY) {
                mOffsetY = offsetY;
                return this;
            }
    
            /**
             * 设置使用系统的toast
             *
             * @param useSystem
             * @return
             */
            public Builder setUseSystem(boolean useSystem) {
                mUseSystem = useSystem;
                return this;
            }
    
            /**
             * 是否取消相同的(相同的不会重新创建,消失之后才能创建新的)
             *
             * @param cancleSame
             * @return
             */
            public Builder setCancleTheSame(boolean cancleSame) {
                mCancleSame = cancleSame;
                return this;
            }
    
            /**
             * 设置自定义view
             *
             * @param layoutId
             * @return
             */
            public Builder setView(@LayoutRes int layoutId) {
                if (layoutId == 0) {
                    throw new NullPointerException("your set layout is null");
                }
                if (null == mContext) {
                    throw new NullPointerException("context  is null");
                }
    
                mlayoutId = layoutId;
                setView(LayoutInflater.from(mContext).inflate(layoutId, null));
                return this;
            }
    
            /**
             * 设置自定义view
             *
             * @param view
             * @return
             */
            public Builder setView(View view) {
                mToastView = view;
                return this;
            }
    
            /**
             * 此方法用于添加toast
             */
            public Builder show() {
                Toastkeeper.this.showToast(mContext, this);
                return this;
            }
    
            /**
             * 此方法用于生命周期结束取消toast
             */
            public void dimiss() {
                Toastkeeper.this.dimissToast();
            }
    
            @Override
            public String toString() {
                String builderString = "";
                if (mlayoutId != 0) {
                    builderString = "Builder{" +
                            "mContext=" + mContext +
                            ", mMessage=" + mMessage +
                            ", mDuration=" + mDuration +
                            ", mGravity=" + mGravity +
                            ", mOffsetX=" + mOffsetX +
                            ", mOffsetY=" + mOffsetY +
                            ", mlayoutId=" + mlayoutId +
                            '}';
                } else {
                    builderString = "Builder{" +
                            "mContext=" + mContext +
                            ", mMessage=" + mMessage +
                            ", mDuration=" + mDuration +
                            ", mGravity=" + mGravity +
                            ", mOffsetX=" + mOffsetX +
                            ", mOffsetY=" + mOffsetY +
                            ", mToastView=" + mToastView +
                            '}';
                }
                return builderString;
            }
        }
    
    
        /**
         * 创建toast
         *
         * @param context
         * @param builder
         */
        private void showToastSafety(Context context, Builder builder) {
    
            if (lastBuilder == null) {
                createDiffToast(context, builder);
            } else {
                boolean sameTag = handleSameToast(builder);
                if (!sameTag) {
                    if (mToast != null) {
                        mToast.cancel();
                    }
                    createDiffToast(context, builder);
                } else {
                    //相同的toast时候
                    if (!isShowing) {
                        createDiffToast(context, builder);
                    }
                }
            }
        }
    
        /**
         * 创建不同的toast根据类型
         * <p>
         * 消息有三种情况
         * 第一系统
         * 第二种默认的
         * 第三中可以自定义布局
         *
         * @param context
         * @param builder
         * @param类型1是相同的toast/类型2是创建新toast
         */
        private void createDiffToast(Context context, Builder builder) {
            if (builder.mUseSystem) {
                if (builder.mMessage == null) {
                    throw new NullPointerException("The message must not be null");
                } else {
                    mToast = Toast.makeText(context, builder.mMessage, Toast.LENGTH_SHORT);
                }
            } else {
                mToast = new Toast(context);
                mToast.setGravity(builder.mGravity, builder.mOffsetX, builder.mOffsetY);
                mToast.setDuration(builder.mDuration);
                View toastView = getToastView(context, builder.mToastView, builder.mMessage);
                mToast.setView(toastView);
            }
    
    
            mToast.show();
            isShowing = true;
            lastBuilder = builder;
    
            sMainHandler.removeMessages(1);
            int mDuration = builder.mDuration == DURATION_LONG ? 3500 : 2000;
            sMainHandler.sendEmptyMessageDelayed(1, mDuration);
    
        }
    
    
        /**
         * 处理相同消息的tag
         * 如果使用系统toast的话,只比较Message,
         * 如果使用自定义的,则比较bean
         * 再次就是需要比较是否主动取消相同的消息
         *
         * @param builder
         * @return
         */
        private boolean handleSameToast(Builder builder) {
            boolean sameBuilder = false;
            boolean mCancleSame = builder.mCancleSame;
            boolean mUseSystem = builder.mUseSystem;
    
            if (mUseSystem) {
                sameBuilder = lastBuilder.mMessage.equals(builder.mMessage);
            } else {
                String lastBuilderS = lastBuilder.toString();
                String currentBuilderS = builder.toString();
                sameBuilder = lastBuilderS.equals(currentBuilderS);
            }
    
            return mCancleSame && sameBuilder;
        }
    
        /**
         * 创建toast的view
         *
         * @param context
         * @param toastView
         * @param mMessage
         * @return
         */
        private View getToastView(Context context, View toastView, CharSequence mMessage) {
            View mToastView = null;
            if (null == toastView) {
                if (mMessage == null) {
                    throw new NullPointerException("The message must not be null");
                } else {
                    if (normalTextView == null) {
                        normalTextView = new TextView(context);
                    }
                    normalTextView.setGravity(Gravity.CENTER);
                    normalTextView.setBackgroundColor(0xEE333333);
                    normalTextView.setTextColor(Color.WHITE);
                    normalTextView.setPadding(50, 35, 50, 35);
                    normalTextView.setText(mMessage);
                    mToastView = normalTextView;
                }
            } else {
                mToastView = toastView;
            }
    
            return mToastView;
        }
    }
    

    相关文章

      网友评论

        本文标题:Android 简单封装Toast工具类

        本文链接:https://www.haomeiwen.com/subject/dsqrwqtx.html