Android之Toast自定义管理

写在前面的话:

现有我们Android使用一个Toast,主要是用来轻量级的提示用户一些小的信息,比如现在弹出5个Toast,但是在Android的历史版本演变中,发现Android7.0系列的版本上,Toast会一个接着一个的弹出,在其他版本上Toast永远只会显示最新的,覆盖掉以前的,基于此,我们为了给用户好一点的体验,希望有一个队列,类似Loop去一直循环消息队列,从而达到自己管理这些Toast,这里分享给各位,水平有限,有不足欢迎评论指出,必定改正!

先分享下我封装的Toast:

功能: 1,支持Toast按照添加顺序一个一个弹出,不会遗漏阻塞某一个Toast
2,支持Toast永远显示最新的内容,不会一次弹出多个给用户体验不好
3,支持自定义Toast布局
4,支持每一个Toast使用自定义布局
5,全局一个Toast,省内存
6,后续再添加新的功能...............

用法:
1,在Application中最简单的初始化方法:

public class MyApplication extends Application {
    private static Context mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        //初始化操作
        FoxToast.init(mContext);
    }
}

这是最懒得也是最简单的写法,当然如果你想要让Toast不要一直弹下去,永远显示最新的,初始化的时候你只需要调用:
FoxToast.init(context,0 new DefaultToastInterfaceImpl(context));
如果你感觉这个布局达不到你的要求,那么你完全可以自己写一个布局文件,放到一个View里,再写一个继承自DefaultToastInterface的实现类比如叫:YourInterfaceImpl,具体写法可以参考默认的实现类DefaultToastView,DefaultToastInterfaceImpl,最终:
要是想永远显示最新的Toast这样写:FoxToast.init(context,0 new YourInterfaceImpl(context))
或者:要是想一个一个弹出来这样写:FoxToast.init(context new YourInterfaceImpl(context))

2,添加Toast:

FoxToast.putMessage("这里写上你要提示的内容");

如果你感觉某一个你要弹出来的Toast布局想要变一下,那么你只需要这样做,参考默认的实现类DefaultToastView,DefaultToastInterfaceImpl,比如你写的这个类叫YourInterfaceImpl,你只需要这样写:
FoxToast.putMessage("这里写上你要提示的内容",new YourInterfaceImpl(context));

OK!,就这两步

分享下写的Toast: 1,这个是Toast设置自定义布局和toaast内容的回调接口


public interface ToastViewInterface {
//获取你想要填充的toast的View
    View getLayoutView();
//这里将toast返回给你,自己可以去放到TextView上
    void setMessage(String msg);
}

2,考虑到有时候比较懒哈哈,所以添加了一个默认的回掉接口实现类,也写了一个默认的布局,当然以一个view来封装的


public class DefaultToastInterfaceImpl implements ToastViewInterface {
    DefaultToastView mToastView;

    public DefaultToastInterfaceImpl(Context context) {
        mToastView = new DefaultToastView(context);
    }

    @Override
    public View getLayoutView() {
        return mToastView;
    }

    @Override
    public void setMessage(String msg) {
        mToastView.setContent(msg);
    }
}
public class DefaultToastView extends LinearLayout {
    private View mToastRoot;

    public TextView getTextView() {
        return mContentTv;
    }

    private TextView mContentTv;

    public DefaultToastView(Context context) {
        this(context, null);
    }

    public DefaultToastView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DefaultToastView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mToastRoot = LayoutInflater.from(context).inflate(R.layout.view_default_toast, this);
        mContentTv = (TextView) mToastRoot.findViewById(R.id.tv_toast_message);
    }

    public View getToastRoot() {
        return mToastRoot;
    }

    public void setContent(String content) {
        if (!TextUtils.isEmpty(content)) {
            mContentTv.setText(content);
        }
    }
}

3,Toast消息的载体仿造Handler的Message.


public class ToastMessage {
    private String msg;
    //一般这里用不到,但是有时候考虑到某一次toast用户想要设置一个不一样的样式
    private ToastViewInterface mToastViewInterface;

    public ToastMessage(String msg) {
        this.msg = msg;
    }

    public ToastMessage(String msg, ToastViewInterface mToastViewInterface) {
        this.msg = msg;
        this.mToastViewInterface = mToastViewInterface;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

    public ToastViewInterface getmToastViewInterface() {
        return mToastViewInterface;
    }

    public void setmToastViewInterface(ToastViewInterface mToastViewInterface) {
        this.mToastViewInterface = mToastViewInterface;
    }
}

4,最重要就是这个ToastManager类了,调度逻辑都是在这里写的


public class ToastManager {
    private static ToastManager mInstance;
    private Context mContext;
    //消息队列
    private List mQueue = new CopyOnWriteArrayList<>();
    //回掉接口
    private ToastViewInterface mToastViewInterface;
    //线程池用来循环读取消息队列
    private Executor mExecutor = Executors.newSingleThreadExecutor();
    //消息间隔时间,目前亲测不同版本不一样,一般设置为0或者大于2000ms起作用
    private static long mIntervalTime = 0;
    private volatile Toast mToast;
    private long mLastTime;
    private final int HANDLE_CODE = 0;

    private Handler mMainHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case HANDLE_CODE:
                    handleToasts((ToastMessage) msg.obj);
                    break;
                default:
                    break;
            }
        }
    };

    static ToastManager getInstance() {
        if (mInstance == null) {
            synchronized (ToastManager.class) {
                if (mInstance == null) {
                    mInstance = new ToastManager();
                }
            }
        }
        return mInstance;
    }

    void init(Context context) {
        init(context, new DefaultToastInterfaceImpl(context));
    }

    void init(Context context, ToastViewInterface in) {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N || Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
            init(context, 1000, in);
        } else {
            init(context, 2050, in);
        }
    }

    void init(Context context, final int intervalTime, ToastViewInterface toastViewInterface) {
        this.mContext = context;
        this.mIntervalTime = intervalTime;
        this.mToastViewInterface = toastViewInterface;
        createToast(context);
        //循环读取消息
        mExecutor.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if (!mQueue.isEmpty()) {
                        if (System.currentTimeMillis() - mLastTime > mIntervalTime) {
                            Message m = Message.obtain();
                            m.what = HANDLE_CODE;
                            m.obj = mQueue.remove(0);
                            mLastTime = System.currentTimeMillis();
                            mMainHandler.sendMessageDelayed(m, 0);
                        }
                    }
                }
            }
        });
    }

    private void createToast(Context context) {
        if (mToast == null) {
            mToast = new Toast(context);
        }
        if (mToastViewInterface != null) {
            mToast.setView(mToastViewInterface.getLayoutView());
        }
    }

    void putMessage(String msg) {
        ToastMessage message = new ToastMessage(msg);
        mQueue.add(message);
    }

    void putMessage(String msg, ToastViewInterface toastViewInterface) {
        ToastMessage message = new ToastMessage(msg, toastViewInterface);
        mQueue.add(message);
    }

    private void handleToasts(final ToastMessage msg) {
        ToastViewInterface customeInterface = msg.getmToastViewInterface();
        //自定义的回掉接口存在表示用户想要为这个消息设置不一样的布局
        if (customeInterface != null) {
            View toastView = customeInterface.getLayoutView();
            if (toastView != null) {
                mToast.setView(toastView);
            }
            customeInterface.setMessage(msg.getMsg());
            mToast.show();
        } else if (mToastViewInterface != null) {
            mToast.setView(mToastViewInterface.getLayoutView());
            mToastViewInterface.setMessage(msg.getMsg());
            mToast.show();
        } else {
            Toast.makeText(mContext, msg.getMsg(), Toast.LENGTH_SHORT).show();
        }

    }

    void setIntervalTime(long intervalTime) {
        this.mIntervalTime = intervalTime;
    }
}

5,为了方便调用,我在ToastManager的外面又封装了一层马甲FoxToast,原因是为了以后扩展只需要改ToastManager的具体实现,而作为调用方,只需继续使用FoxToast就行了,改动小一些


public class FoxToast {
    public static void init(Context context) {
        ToastManager.getInstance().init(context);
    }

    public static void init(Context context, ToastViewInterface in) {
        ToastManager.getInstance().init(context, in);
    }

    public static void init(Context context, int intervalTime, ToastViewInterface in) {
        ToastManager.getInstance().init(context, intervalTime, in);
    }

    public static void putMessage(String msg) {
        ToastManager.getInstance().putMessage(msg);
    }

    public static void putMessage(String msg, ToastViewInterface toastViewInterface) {
        ToastManager.getInstance().putMessage(msg, toastViewInterface);
    }

    public static void setIntervalTime(long intervalTime) {
        ToastManager.getInstance().setIntervalTime(intervalTime);
    }
}

你可能感兴趣的:(android)