利用IToast实现滚动文字的toast(Toast方面)

最近产品提了一个想让我拿刀的问题,一个提示文字要在其他app在顶层的时候也显示,不能干扰用户操作,文字必须是可以滚动,时长为30秒(啥啥啥都是啥),做安卓的都知道toast只能设置为2s和3.5s,其它的值都无效,API的文档虽然写的第三个参数是时间,但是Framework里作了重定义,限定了2s和3.5s这两个值,对应 Toast.LENGTH_SHORT和Toast.LENGTH_LONG,但是测试不会管你安卓是怎么限制的,实现不出就是你自己能力不行,为了保住饭碗,问遍了度娘及其他的大佬,终于搞出了一个让Toast持续显示的方案:

```

public void showMyToast(final Toast toast, final int cnt) {

 final Timer timer =new Timer();

    timer.schedule(new TimerTask() {

        @Override

        public void run() {

        toast.show();

    }

    },0,3000);

    new Timer().schedule(new TimerTask() {

        @Override

        public void run() {

        toast.cancel();

        timer.cancel();

    }

    }, cnt );

}

```

调用:

Toast toast=Toast.makeText(RegistActivity.this,"这是可以随意设置时间的Toast", Toast.LENGTH_LONG);showMyToast(toast,10*1000);// 设置显示时间

你每次要关的时候我就调用show()方法,直到我Timer计时完毕,网上最传广的方法,优点是全原生,只需要加个控制类就行,但是立马被测试打回来了,为啥?因为其实这只是伪显示,每3秒都是重新打开的,所以滚动文字每三秒就回到开始重新轮播,产品的需求是10秒一滚,它滚不了你就给我滚,,,好吧,既然别人是一种不要你觉得我要我觉得的态度,我也只能重新做了。。。有发现zhitaocai大佬为了解决当时MIUI4 toast不显示的问题把toast重写了一遍实现了完整的setDuration方法,(github地址:https://github.com/zhitaocai/ToastCompat_Deprecated)不过内部的view是写死的,如果只需要使用普通的toast的话只需引入依赖库之后直接ToastCompat.make(Contextcontext,Stringtext,longduration).show();

就可以愉快的使用了,但是如果需要像我一样实现滚动文字和文字前logo的话就必须对MIUItoast类进行重写,在IToast setText方法中自定义view和内容然后setview(view),具体代码如下:

```

    public class MIUIToastimplements IToast {

private static HandlermHandler =new Handler();

    public AutoMarqueeTextViewGeTuiToastUtilMessage;

    public ImageViewGeTuiToastUtilImage;

    public ViewGeTuiToastUtilView;

    /**

* 维护toast的队列

*/

    private static BlockingQueuemQueue =new LinkedBlockingQueue<>();

    /**

    * 原子操作:判断当前是否在读取{@linkplain #mQueue 队列}来显示toast

*/

    protected static AtomicIntegermAtomicInteger =new AtomicInteger(0);

    private WindowManagermWindowManager;

    private long mDurationMillis;

    private ViewmView;

    private WindowManager.LayoutParamsmParams;

    private ContextmContext;

    public static IToastmakeText(Context context, String text, long duration) {

return new MIUIToast(context).setText(text).setDuration(duration)

.setGravity(Gravity.TOP, 0, DisplayUtil.dip2px(context, 10));

    }

public MIUIToast(Context context) {

mContext = context;

        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);

        mParams =new WindowManager.LayoutParams();

        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

        mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;

        mParams.format = PixelFormat.TRANSLUCENT;

        mParams.windowAnimations = android.R.style.Animation_Toast;

        mParams.type = WindowManager.LayoutParams.TYPE_TOAST;

        mParams.setTitle("Toast");

        mParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |

WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        // 默认小米Toast在下方居中

        mParams.gravity = Gravity.TOP ;

    }

/**

* Set the location at which the notification should appear on the screen.

*

    * @param gravity

    * @param xOffset

    * @param yOffset

    */

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)

@Override

    public IToastsetGravity(int gravity, int xOffset, int yOffset) {

// We can resolve the Gravity here by using the Locale for getting

// the layout direction

        final int finalGravity;

        if (Build.VERSION.SDK_INT >=14) {

final Configuration config =mView.getContext().getResources().getConfiguration();

            finalGravity = Gravity.getAbsoluteGravity(gravity, config.getLayoutDirection());

        }else {

finalGravity = gravity;

        }

mParams.gravity = finalGravity;

        if ((finalGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {

mParams.horizontalWeight =1.0f;

        }

if ((finalGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {

mParams.verticalWeight =1.0f;

        }

mParams.y = yOffset;

        mParams.x = xOffset;

return this;

    }

@Override

    public IToastsetDuration(long durationMillis) {

if (durationMillis <0) {

mDurationMillis =0;

        }

if (durationMillis == Toast.LENGTH_SHORT) {

mDurationMillis =2000;

        }else if (durationMillis == Toast.LENGTH_LONG) {

mDurationMillis =3500;

        }else {

mDurationMillis = durationMillis;

        }

return this;

    }

/**

    * 不能和{@link #setText(String)}一起使用,要么{@link #setView(View)} 要么{@link #setView(View)}

*

    * @param view

    *

    * @return

    */

    @Override

    public IToastsetView(View view) {

mView = view;

return this;

    }

@Override

    public IToastsetMargin(float horizontalMargin, float verticalMargin) {

mParams.horizontalMargin = horizontalMargin;

        mParams.verticalMargin = verticalMargin;

return this;

    }

/**

    * 不能和{@link #setView(View)}一起使用,要么{@link #setView(View)} 要么{@link #setView(View)}

*

    * @return

    */

    @Override

    public IToastsetText(String text) {

// 模拟Toast的布局文件 com.android.internal.R.layout.transient_notification

// 虽然可以手动用java写,但是不同厂商系统,这个布局的设置好像是不同的,因此我们自己获取原生Toast的view进行配置

        GeTuiToastUtilView = LayoutInflater.from(mContext).inflate(R.layout.toast_layout, null);

        if (GeTuiToastUtilView !=null) {

GeTuiToastUtilMessage =GeTuiToastUtilView.findViewById(R.id.geTuiToastUtilMessage);

            GeTuiToastUtilImage = (ImageView)GeTuiToastUtilView.findViewById(R.id.toast_image);

            GeTuiToastUtilMessage.setTextColor(ScnResourceUtil.getColor(mContext, R.color.scn_color_EBEBEB));

            GeTuiToastUtilMessage.setTextSize(TypedValue.COMPLEX_UNIT_PX, ScnResourceUtil.getDimen(mContext, R.dimen.dimen_12sp));

            GeTuiToastUtilMessage.setMaxWidth(ScnResourceUtil.getDimen(mContext,R.dimen.dimen_574dp));

            GeTuiToastUtilMessage.setScrollStep(ScnResourceUtil.getDimen(mContext,R.dimen.dimen_200dp));

            GeTuiToastUtilMessage.setMaxLines(1);

            GeTuiToastUtilMessage.setRndDuration(10);

            GeTuiToastUtilMessage.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);

            setView(GeTuiToastUtilView);

            GeTuiToastUtilMessage.setText(text.isEmpty() ?"null" : text);

            GeTuiToastUtilMessage.post(() ->GeTuiToastUtilMessage.startMarquee());

            this.setGravity(Gravity.TOP,0,20);

        }

return this;

    }

@Override

    public void show() {

// 1. 将本次需要显示的toast加入到队列中

        mQueue.offer(this);

        // 2. 如果队列还没有激活,就激活队列,依次展示队列中的toast

        if (0 ==mAtomicInteger.get()) {

mAtomicInteger.incrementAndGet();

            mHandler.post(mActivite);

        }

}

@Override

    public void cancel() {

// 1. 如果队列已经处于非激活状态或者队列没有toast了,就表示队列没有toast正在展示了,直接return

        if (0 ==mAtomicInteger.get() &&mQueue.isEmpty()) {

return;

        }

// 2. 当前显示的toast是否为本次要取消的toast,如果是的话

// 2.1 先移除之前的队列逻辑

// 2.2 立即暂停当前显示的toast

// 2.3 重新激活队列

        if (this.equals(mQueue.peek())) {

mHandler.removeCallbacks(mActivite);

            mHandler.post(mHide);

            mHandler.post(mActivite);

        }

//TODO 如果一个Toast在队列中的等候展示,当调用了这个toast的取消时,考虑是否应该从对队列中移除,看产品需求吧

    }

private void handleShow() {

if (mView !=null) {

if (mView.getParent() !=null) {

mWindowManager.removeView(mView);

            }

mWindowManager.addView(mView, mParams);

        }

}

private void handleHide() {

if (mView !=null) {

// note: checking parent() just to make sure the view has

// been added...  i have seen cases where we get here when

// the view isn't yet added, so let's try not to crash.

            if (mView.getParent() !=null) {

mWindowManager.removeView(mView);

                // 同时从队列中移除这个toast

                mQueue.poll();

            }

mView =null;

        }

}

private static void activeQueue() {

MIUIToast miuiToast =mQueue.peek();

        if (miuiToast ==null) {

// 如果不能从队列中获取到toast的话,那么就表示已经暂时完所有的toast了

// 这个时候需要标记队列状态为:非激活读取中

            mAtomicInteger.decrementAndGet();

        }else {

// 如果还能从队列中获取到toast的话,那么就表示还有toast没有展示

// 1. 展示队首的toast

// 2. 设置一定时间后主动采取toast消失措施

// 3. 设置展示完毕之后再次执行本逻辑,以展示下一个toast

            mHandler.post(miuiToast.mShow);

            mHandler.postDelayed(miuiToast.mHide, miuiToast.mDurationMillis);

            mHandler.postDelayed(mActivite, miuiToast.mDurationMillis);

        }

}

private final RunnablemShow =new Runnable() {

@Override

        public void run() {

handleShow();

        }

};

    private final RunnablemHide =new Runnable() {

@Override

        public void run() {

handleHide();

        }

};

    private final static RunnablemActivite =new Runnable() {

@Override

        public void run() {

activeQueue();

        }

};

}

```

这里感谢非花非雾--大佬的修改方案,这里用的是自定义方案三

你可能感兴趣的:(利用IToast实现滚动文字的toast(Toast方面))