[关闭]
@linux1s1s 2017-01-22T16:52:03.000000Z 字数 4439 阅读 8110

Android Toast 实现自定义时间

AndroidWidget 2015-10


方法一:通过UI线程检测显示时间(显示时间需要在3.5s 以下)

该方法直接通过Toast API,只是加了一步操作:检测显示的时间,超过这个时间直接cancel即可。

自定义的Toast View

  1. @SuppressLint("InflateParams")
  2. public static View createToastLayout(CharSequence str, Context a, boolean supportTextType) {
  3. View pgLayout = supportTextType ? LayoutInflater.from(a).inflate(R.layout.xxxx, null) : LayoutInflater.from(a).inflate(
  4. R.layout.xxxxxx_hint, null);
  5. TangFontTextView tv = (TangFontTextView) pgLayout.findViewById(R.id.toast_textview);
  6. if(!TextUtils.isEmpty(str)){
  7. tv.setText(str);
  8. }
  9. return pgLayout;
  10. }

Toast初始化。

  1. public static Toast createToast(CharSequence str, Context a, boolean supportTextType){
  2. View pgLayout = createToastLayout(str, a, supportTextType);
  3. Toast toast = new Toast(a);
  4. toast.setView(pgLayout);
  5. toast.setDuration(Toast.LENGTH_LONG);
  6. toast.setGravity(Gravity.CENTER, 0, 0);
  7. return toast;
  8. }

Toast显示和检测时间

  1. public void showRemoveRemindTips(final BaseSherlockActivity activity, final String tips){
  2. final Toast toast = CustomToast.createToast(tips, activity, false);
  3. toast.show();
  4. mHandler.postDelayed(new Runnable() {
  5. @Override
  6. public void run() {
  7. toast.cancel();
  8. }
  9. }, 1500);
  10. }

方法二:通过反射去修改Toast显示时间(无时间限制)

该方法来自网络-Android中通过反射来设置Toast的显示时间,并部分修改,特此说明。

这个方法是网上通用的方法,适合显示时间任意自定义的情况,具体的思路如下:
首先借助TN类,所有的显示逻辑在这个类中的show方法中,然后再实例一个TN类变量,将传递到一个队列中进行显示,所以我们要向解决这个显示的时间问题,那就从入队列这部给截断,因为一旦toast入队列了,我们就控制不了,因为这个队列是系统维护的,所以我们现在的解决思路是:

1、不让toast入队列
2、然后我们自己调用TN类中的show和hide方法

第一个简单,我们不调用toast方法就可以了,但是第二个有点问题了,因为我们看到TN这个类是私有的,所以我们也不能实例化他的对象,但是toast类中有一个实例化对象:tn

  1. final TN mTN;

该成员变量是包访问权限,所以需要借助反射,我们只需要反射出这个变量就可以得到这个TN类对象了,然后再使用反射获取他的show和hide方法即可,下面我们就来看一下实际的代码吧:

  1. package com.weijia.toast;
  2. import java.lang.reflect.Field;
  3. import java.lang.reflect.Method;
  4. import android.content.Context;
  5. import android.view.View;
  6. import android.widget.Toast;
  7. public class ReflectToast {
  8. Context mContext;
  9. private Toast mToast;
  10. private Field field;
  11. private Object obj;
  12. private Method showMethod, hideMethod;
  13. public ReflectToast(Context c, View v) {
  14. this.mContext = c;
  15. mToast = new Toast(mContext);
  16. mToast.setView(v);
  17. reflectionTN();
  18. }
  19. public void show() {
  20. try {
  21. showMethod.invoke(obj, null);
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. public void cancel() {
  27. try {
  28. hideMethod.invoke(obj, null);
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. private void reflectionTN() {
  34. try {
  35. field = mToast.getClass().getDeclaredField("mTN");
  36. field.setAccessible(true);//强暴
  37. obj = field.get(mToast);
  38. showMethod = obj.getClass().getDeclaredMethod("show", null);
  39. hideMethod = obj.getClass().getDeclaredMethod("hide", null);
  40. } catch (Exception e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. }

这里我们实例化一个Toast对象,但是没有调用showf方法,就是不让toast入系统显示队列中,这样就可以控制show方法和hide方法的执行了,下面是测试代码:

  1. package com.weijia.toast;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.view.View.OnClickListener;
  6. import android.widget.TextView;
  7. public class MainActivity extends Activity {
  8. ReflectToast toast;
  9. boolean isShown = false;
  10. @Override
  11. public void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_main);
  14. final TextView tView = new TextView(this);
  15. tView.setText("ReflectToast !!!");
  16. toast = new ReflectToast(this, tView);
  17. findViewById(R.id.show_toast).setOnClickListener(new OnClickListener() {
  18. @Override
  19. public void onClick(View v) {
  20. if(isShown){
  21. toast.cancel();
  22. isShown = false;
  23. }else{
  24. toast.show();
  25. isShown = true;
  26. }
  27. }
  28. });
  29. }
  30. }

注意:这里有一个问题,我开始的时候用三星手机测试的,没有任何效果,然后换成小米手机也不行,最后用模拟器测试是可以的了。具体原因还在解决中。。。

方法三:通过轮询保持显示(显示时间需要在2.5s 以上)

该方法来自网络-Android进阶篇-Toast自定义显示时间,不说废话,直接上干货。

  1. public class CustomToast {
  2. public static final int LENGTH_MAX = -1;
  3. private boolean mCanceled = true;
  4. private Handler mHandler;
  5. private Context mContext;
  6. private Toast mToast;
  7. public CustomToast(Context context) {
  8. this(context,new Handler());
  9. }
  10. public CustomToast(Context context,Handler h) {
  11. mContext = context;
  12. mHandler = h;
  13. mToast = Toast.makeText(mContext,"",Toast.LENGTH_SHORT);
  14. mToast.setGravity(Gravity.BOTTOM, 0, 0);
  15. }
  16. public void show(int resId,int duration) {
  17. mToast.setText(resId);
  18. if(duration != LENGTH_MAX) {
  19. mToast.setDuration(duration);
  20. mToast.show();
  21. } else if(mCanceled) {
  22. mToast.setDuration(Toast.LENGTH_LONG);
  23. mCanceled = false;
  24. showUntilCancel();
  25. }
  26. }
  27. /**
  28. * @param text 要显示的内容
  29. * @param duration 显示的时间长
  30. * 根据LENGTH_MAX进行判断
  31. * 如果不匹配,进行系统显示
  32. * 如果匹配,永久显示,直到调用hide()
  33. */
  34. public void show(String text,int duration) {
  35. mToast.setText(text);
  36. if(duration != LENGTH_MAX) {
  37. mToast.setDuration(duration);
  38. mToast.show();
  39. } else {
  40. if(mCanceled) {
  41. mToast.setDuration(Toast.LENGTH_LONG);
  42. mCanceled = false;
  43. showUntilCancel();
  44. }
  45. }
  46. }
  47. /**
  48. * 隐藏Toast
  49. */
  50. public void hide(){
  51. mToast.cancel();
  52. mCanceled = true;
  53. }
  54. public boolean isShowing() {
  55. return !mCanceled;
  56. }
  57. private void showUntilCancel() {
  58. if(mCanceled)
  59. return;
  60. mToast.show();
  61. mHandler.postDelayed(new Runnable() {
  62. public void run() {
  63. showUntilCancel();
  64. }
  65. },3000);
  66. }
  67. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注