Android 簡單封裝Toast工具類

今天在此分享一個之前自己封裝的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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章