android的toast怎么自定义显示时间长度?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android的toast怎么自定义显示时间长度?相关的知识,希望对你有一定的参考价值。

android新手求解

Android中Toast的显示时间为特定时间且不可更改,但是有时候我们开发设计需要让Toast显示更长时间,或者自己完全控制Toast的显示和关闭。通过查看Toast类的源码,可以看出,这有点难为它了,Toast类本身并没有提供相应方法。

  但是通过源码的查看,还是可以看出点眉头。源码分析思路在这里转eoe里的一篇文章,思路较为清晰:

  转:

  Toast信息提示框之所以在显示一定时间后会自动关闭,是因为在系统中有一个Toast队列。系统会依次从队列中取(出队列)一个Toast,并 显示它。在显示一段时间后,再关闭,然后再显示下一个Toast信息提示框。

直到Toast队列中所有Toast都显示完为止。那么有些时候需要这个Toas t信息提示框长时间显示,直到需要关闭它时通过代码来控制,而不是让系统自动来关闭Toast信息提示框。

不过这个要求对于Toast本身来说有些过 分,因为Toast类并没有提供这个功能。虽然如此,但方法总比问题多。通过一些特殊的处理还是可以实现这个功能的,而且并不复杂。

  Toast信息提示框需要调用Toast.show方法来显示。下面来看一下show方法的源代码。

  public void show()

  if (mNextView == null)

  throw new RuntimeException("setView must have been called");

  

  INotificationManager service = getService();

  String pkg = mContext.getPackageName();

  TN tn = mTN;

  try

  // 将当前Toast加入到Toast队列

  service.enqueueToast(pkg, tn, mDuration);

   catch (RemoteException e)

  // Empty

  

  
复制代码

  show方法的代码并不复杂,可以很容易找到如下的代码。
 
 service.enqueueToast(pkg, tn, mDuration);
复制代码

  从上面的代码可以很容易推断出它的功能是将当前的Toast加入到系统的Toast队列中。

看到这里,各位读者应该想到。虽然show方法的表面功能是显示Toast信息提示框,但其实际的功能是将Toast加入到队列中,再由系统根据Toast队列来显示Toast信息提示框。那么我们经过更进一步地思考,可以大胆地做出一个初步的方案。

既然系统的Toast队列可以显示Toast信息提示框,那么我们为什么不可以自己来显示它呢?

这样不是可以自己来控制Toast的信息提示框的显示和关闭了吗!当然,这就不能再调用show方法来显示Toast信息提示框了(因为show方法会将Toast加入队列,这样我们就控制不了Toast了)。

  既然初步方案已拟定,现在就来实施它。先在Toast类找一下还有没有其他的show方法。

结果发现了一个TN类,该类是Toast的一个内嵌类。在TN类中有一个show方法。TN是ITransientNotification.Stub的子类。从ITransientNotification和TN类中的show方法初步推断(因为Transient的中文意思是“短暂的”)系统是从Toast队列中获得了Toast对象后,利用TN对象的show方法显示Toast,再利用TN.hide方法来关闭Toast。

首先声明,这只是假设,我们还不知道这么做是否可行!当然,这也是科学研究的一般方法,先推断或假设,然后再证明推断或假设。

  现在关键的一步是获得TN对象。遗憾的是TN被声明成private类型,外部无法访问。不过别着急。在Toast类中有一个mTN变量。虽然不是public变量,但仍然可以通过反射技术访问该变量。mTN变量会在创建Toast对象时初始化。

因此,只要获得mTN变量,就获得了TN对象。下面的代码显示了一个永远不会自动关闭的Toast信息提示框。

  // 先创建一个Toast对象  Toast toast = Toast.makeText(this, "永不消失的Toast", Toast.LENGTH_SHORT);  // 设置Toast信息提示框显示的位置(在屏幕顶部水平居中显示)  toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0);  try  

  // 从Toast对象中获得mTN变量  Field field = toast.getClass().getDeclaredField("mTN");

  field.setAccessible(true);

  Object obj = field.get(toast);

  // TN对象中获得了show方法

  Method method = obj.getClass().getDeclaredMethod("show", null);

  // 调用show方法来显示Toast信息提示框

  method.invoke(obj, null);

  

  catch (Exception e)

  

  
复制代码

  上面的代码中try…catch(…)…语句中的代码是关键。先利用事先创建好的Toast对象获得了mTN变量。然后再利用反射技术获得了TN对象的show方法。

  关闭Toast和显示Toast的方法类似,只是需要获得hide方法,代码如下:

  try

  

  // 需要将前面代码中的obj变量变成类变量。这样在多个地方就都可以访问了

  Method method = obj.getClass().getDeclaredMethod("hide", null);

  method.invoke(obj, null);

  

  catch (Exception e)

  

  
复制代码

  上面的代码已经很完美地实现了通过代码控制Toast信息提示框显示和关闭的功能。

但如果想实现得更完美,可以在Android SDK源代码中找一个叫ITransientNotification.aidl的文件(该文件是AIDL服务定义文件,将在后面详细介绍),并在Android工程的src目录中建一个android.app包,将这个文件放到这个包中。

然后ADT会自动在gen目录中生成了一个android.app包,包中有一个ITransientNotification.java文件。由于Android SDK自带的ItransientNotification接口属于内部资源,外部程序无法访问,因此,只能将从Toast对象中获得的mTN变量转换成刚才生成的ITransientNotification对象了。

这样就不需要使反射技术获得show和hide方法了。

经过改良的显示和关闭Toast信息提示框的代码如下:

  ITransientNotification notification = (ITransientNotification) field.get(toast);

  // 显示Toast信息提示框

  notification.show();

  // 关闭Toast信息提示框

  notification.hide();
复制代码

  最后整理代码如下:

  Java代码

import java.lang.reflect.Field;

  import java.lang.reflect.Method;

  import android.app.Activity;

  import android.os.Bundle;

  import android.view.Gravity;

  import android.view.View;

  import android.widget.Button;

  import android.widget.Toast;

  public class TestToastActivity extends Activity

  private Button showtoast,closetoast;

  private Toast toast;

  private Field field;

  private Object obj;

  private Method showMethod,hideMethod;

  @Override

  public void onCreate(Bundle savedInstanceState)

  super.onCreate(savedInstanceState);

  setContentView(R.layout.main);

  //初始化按钮组件

  showtoast = (Button)this.findViewById(R.id.showtoast);

  closetoast = (Button)this.findViewById(R.id.closetoast);

  //设置组件监听

  showtoast.setOnClickListener(new MyOnClickListener());

  closetoast.setOnClickListener(new MyOnClickListener());

  //创建Toast对象

  toast = Toast.makeText(this, "Toast自定义显示时间测试", 1);

  toast.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);

  //利用反射技术拿到mTN对象

  reflectionTN();

  

  class MyOnClickListener implements View.OnClickListener

  @Override

  public void onClick(View v)

  switch (v.getId())

  case R.id.showtoast:

  try

  showMethod.invoke(obj, null);//调用TN对象的show()方法,显示toast

   catch (Exception e)

  e.printStackTrace();

  

  break;

  case R.id.closetoast:

  try

  hideMethod.invoke(obj, null);//调用TN对象的hide()方法,关闭toast

   catch (Exception e)

  e.printStackTrace();

  

  break;

  default:

  break;

  

  

  

  private void reflectionTN()

  try

  field = toast.getClass().getDeclaredField("mTN");

  field.setAccessible(true);

  obj = field.get(toast);

  showMethod = obj.getClass().getDeclaredMethod("show", null);

  hideMethod = obj.getClass().getDeclaredMethod("hide", null);

   catch (Exception e)

  e.printStackTrace();

  

  

  
复制代码
参考技术A 假如:
Toast.makeText(context,msg,Toast.LENGTH_SHORT).show(); 这个是短时时间显示;
Toast.makeText(context,msg,Toast.LENGTH_LONG).show(); 这个是长时时间显示;
参考技术B 只有long 和shot两种模式。。

Android快速开发常用知识点系列目录

项目构建

Android项目目录结构模板以及简单说明【简单版】

Android Studio配置统一管理依赖版本号引用

Android多Module下的Application引用方式

APP开篇

Android 8.0系统的应用图标适配

Android APP应用启动页白屏(StartingWindow)优化

全面屏适配以及启动页适配(采用制作.9图的方式)

WelcomeActivity【欢迎界面】

PermissionDialog【权限申请提示对话框】

Android6.0运行时权限(基于RxPermission开源库)

Android状态栏着色

Android屏幕适配和方案【整理】

Toast篇章

ToastUtil【简单的Toast封装类】【未自定义Toast的显示风格】

ToastCustom【自定义显示风格的Toast】

ToastMiui【仿MIUI的带有动画的Toast】

ToastCustomUtil【简单的Toast封装类】【自定义Toast的显示风格】

Log篇章

LogUtil【实现自由的控制日志的打印的封装类】

LogcatHelperDemo【应用log信息保存成本地文件】

常用util工具类篇章

ColorUtil【Color工具类(color整型、rgb数组、16进制互相转换)】

DensityUtil【尺寸转换工具类(px、dp互相转换)】

HttpUtil 【判断网络连接的封装类】

WebUtils【MD5加密(基于MessageDigest)】

ACache【轻量级的开源缓存框架】【不建议使用】

PreferencesUtils【SharedPreferences操作工具类】

DateTimeHelper【日期类型与字符串互转以及日期对比相关操作】

DeviceUuidFactory【获取设备唯一标识码的UUID(加密)】【需要运行时权限的处理的配合】

IntentActionUtil【Intent的常见作用的工具类】

FileUtils【获取SD卡根目录、读写文件、移动、复制、删除文件、获取文件名、后缀名操作类】【不建议使用这个工具类】

AppDir【创建缓存目录】【建议使用这个工具类】

FileSizeUtil【获取文件夹或文件的大小】

GetPathFromUri4kitkat【Android 4.4 kitkat以上及以下根据uri获取路径的方法】

AssetsUtils【读取assets、res/raw、./data/data/包名/目录下的文件】

AntZipUtils【基于Ant的Zip压缩解压缩工具类】

ResDrawableImgUtil【根据图片名称获取resID值或者Bitmap对象】

NetStateReceiver【监听网路状态变化】

WindowUtils【窗口工具类】

NavUtils【底部虚拟导航栏工具类】

BitmapUtil【缩放bitmap以及将bitmap保存成图片到SD卡中】

Cache【硬盘缓存工具类(包含内存缓存LruCache和磁盘缓存DiskLruCache)】

AppUtils【获取手机的信息和应用版本号、安装apk】

KeyboardUtil【软键盘弹出后输入框上移一定的高度】

EscapeAndUnescapeUtil【java模拟js的escape和unescape函数】

LongLightUtils【保持屏幕常亮工具类】

ShareIntentUtil【调用系统自带的分享的工具类】

NotificationSetUtilDemo【判断APP通知栏权限是否开启,以及如何跳转到应用程序设置界面】

RomUtil【Android判断手机ROM,用于判断手机机型】

AutoStartUtil【打开自启动设置界面】

Activity跳转篇章

Activity、Fragment、Dialog基类简单整理

ActivityJump+ActivityManager【Activity之间的跳转和Activity任务栈管理】

下拉菜单篇章

SpinnerViewPop【PopWindow样式(单选)、Dialog样式(单选+多选)的下拉菜单】

Android-PickerView【仿iOS的PickerView控件,并封装了时间选择和选项选择这两种选择器】使用

对话框篇章

ProgressWheelDialogUtil【ProgressWheel Material样式进度条对话框】

ConfirmCancelUtilDialog【确认取消对话框封装类】

ConfirmCancelDialog【确认取消对话框】

AlertConfirmDialog【基于AlertDialog的确认取消对话框】

ConfirmCancelBottomSheetDialog【确认取消底部对话框】

ArticleRemoveDelDialog【基于AlertDialog的回收删除对话框】

NormalDialogFragmentDemo【普通页面的DialogFragment】

NewBuiltBottomSheetDialog【新建底部对话框】

PopupWindowMenuUtil【popupwindow样式菜单项列表】

MaterialCalendarDialog【Material样式的日历对话框】

ShareDialogDemo【分享对话框】

网络请求篇章

okhttputils【 Android 一个改善的okHttp封装库】使用(一)

okhttputils【 Android 一个改善的okHttp封装库】使用(二)

okhttputils【 Android 一个改善的okHttp封装库】使用(三)

发现新版本篇章

 

数据库篇章

Litepal【开源数据库ORM框架】【版本是1.6.1,需要升级到2.0.0】

LitepalNewDemo【开源数据库ORM框架-LitePal2.0.0版本的使用】

选项卡篇章

TabBottomFragmentLayout【自定义底部选项卡区域(搭配Fragment)】【有时候会这样用,有时候使用FragmentTabHost】

TabTopLayout【自定义顶部选项卡区域(固定宽度且居中)】【有时候会这样用】

TabTopUnderLineLayout【自定义顶部选项卡(带下划线)】【了解即可】

TabTopAutoLayout【自定义顶部选项卡区域(带下划线)(动态选项卡数据且可滑动)】【一般使用TabLayout+ViewPager】

TabTopAutoTextSizeLayout【自定义文字字号区域(动态选项卡数据且可滑动)】

FragmentTabHostBottomDemo【FragmentTabHost + Fragment实现底部选项卡】

FragmentTabHostTopDemo【FragmentTabHost固定宽度且居中】【演示部分功能的用法】

FragmentTabHostUnderLineDemo【FragmentTabHost带下划线】【演示部分功能的用法】

FragmentTabHostAutoDemo【FragmentTabHost可滑动的选项卡】【演示部分功能的用法】【一般使用TabLayout+ViewPager】

TabLayoutViewPagerDemo【TabLayout+ViewPager可滑动】

TabLayoutBottomDemo【TabLayout实现底部选项卡】【一般不这样用】

EditText输入框篇章

Android中EditText显示明文与密文的两种方式

DownEditTextView【自定义Edittext对Android 软键盘向下的监听】

 

RecyclerView篇章

RecyclerViewItemTouchHelperDemo【使用ItemTouchHelper进行拖拽排序功能】

RecyclerSwipeAdapterDemo【使用AndroidSwipeLayout用于列表项侧滑功能】

RecyclerFullyManagerDemo【ScrollView里嵌套Recycleview的自适应高度功能】

RecyclerViewSelectableAdapterDemo【封装BaseSelectableAdapter用于多选、单选,以及切换选中状态等功能】

RecyclerViewLoadMoreDemo【封装上拉加载功能的RecyclerView,搭配SwipeRefreshLayout实现下拉刷新】

RecyclerFlexboxLayoutManagerDemo【使用FlexboxLayoutManager实现流式布局】

VLayoutDemo【VLayout的简单使用demo(基于V1.2.8版本)】

Glide篇章

GlideDemo【Glide3.7.0版本的简单使用以及圆角功能】

GlideNewDemo【Glide4.7.1版本的简单使用以及圆角功能】

PhotoPicker篇章

PhotoPickerDemo【PhotoPicker0.9.8的个性化修改以及使用(内部glide版本号是3.7.0)】

PhotoPickerNewDemo【PhotoPicker0.9.12的个性化修改以及使用(内部glide版本号是4.1.1)】

WebView篇章

MyWebViewDemo【封装Webview常用配置和选择文件、打开相机、录音、打开本地相册的用法】

MyBridgeWebViewDemo【集成JsBridge开源库的的封装的webview】

MyX5TbsPlusDemo【体验腾讯浏览服务Android SDK (TbsPlus 版)】

MyX5TbsDemo【体验腾讯浏览服务Android SDK (完整版)】

多语言篇章

 

Material Design篇章

ToolbarDemo【Toolbar作为顶部导航栏的简单使用】

PopupMenuDemo【popupMenu的简单使用】

DrawerLayoutDemo【侧边栏(侧滑菜单)简单实现】

NavigationViewDemo【和DrawerLayout搭配使用实现侧滑导航视图界面】

FloatingActionButtonDemo【悬浮按钮的使用,顺带snackBar的使用】

SnackbarUtilDemo【Snackbar的封装类】

CollapsingToolbarLayoutDemo【可折叠式标题栏,顺便带有CardView卡片式布局】

ConstraintLayoutDemo【约束性布局知识梳理】【基于1.1.3】

ViewPager篇章

ViewPagerWithRecyclerDemo【RecyclerView+ViewPager实现类似TabLayout+ViewPager效果】

ViewPagerWithViewDemo【ViewPager和View搭配以及演示获取里面的值和CheckBox单选效果】

ViewPagerWithImageDemo【ViewPager如何判断滑动到第一页和最后一页以及弹出对话框功能】

百度篇章

BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.7.3)

BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.8.1)

友盟篇章

UmengAppDemo【友盟统计SDK集成以及多渠道打包配置,基于V7.5.3版本】

UmengShareDemo【友盟分享SDK集成,基于V6.9.3版本】

推送篇章

JPushDemo【极光推送集成,基于v3.1.8版本】

HWPushDemo【华为推送集成,基于2.6.1.301版本】

XiaomiPushDemo【小米推送集成,基于V3.6.12版本】

轮播图控件篇章

BannerDemo【图片轮播图控件】

 

其他篇章

ShortcutBadgerDemo【安卓应用角标(badge)实现方案】

Android根据word模板文档将表单数据生成word文档的方案整理

 

Android加密篇章

 

以上是关于android的toast怎么自定义显示时间长度?的主要内容,如果未能解决你的问题,请参考以下文章

Toast拓展--自定义显示时间和动画

Android Toast 自定义显示时长

Toast拓展--自定义显示时间和动画

Android基础:自定义带图片的Toast

Android基础:自定义带图片的Toast

android自定义Toast之-弹出消息