好吧,知识来源于实践。最近项目有一个功能,要在全局范围内实现提示功能,最后采用了Toast的方式(没办法,这种app级的弱提示,还是Toast来的方便),研究了下源码,做了一个自定义的吐司。记录一下。
Toast 应该接触过android的都知道,而且应用起来相当简单。
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
上面的是最简单的Toast应用,Toast类的makeText方法有三个参数,上下文,提示内容和显示时间(Toast中给出两种选择。Toast.LENGTH_SHORT:2000ms, Toast.LENGTH_LONG:3500ms),然后此方法返回一个Toast类的实例。在调用show()方法,显示出来。
大家用toast的时候,可能注意到了,当一个按钮点击事件弹出吐司的时候,如果我们一直点,它就会一直提示,当我们停止动作的时候,也会响应一段时间,这就说明,toast不是实时响应的,内部应该有一个队列。这个后面讲原理的时候,会详细说明。
SDK中的Toast功能还是有很多种实现的,用起来还是很方便的:
更改显示位置
Toast toast = Toast.makeText(MainActivity.this, "欢迎光临阿东的博客", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.show();
主要方法 setGravity(int gravity, int xOffset, int yOffset) ,第二个参数和第三个参数对应X轴和Y轴的偏移量
添加View
Toast toast = Toast.makeText(MainActivity.this, "欢迎光临阿东的博客", Toast.LENGTH_LONG);
LinearLayout toastView = (LinearLayout) toast.getView();// 获取Toast的LinearLayout,注意需要是线性布局
ImageView image = new ImageView(MainActivity.this);
image.setImageResource(R.drawable.ic_launcher);// 生成一个现实Logo的ImageView
toastView.addView(image);// 将ImageView加载到LinearLayout上面
toast.show();
说到这,我贴一下Toast布局的源码吧,看代码,一目了然
transient_notification.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="?android:attr/toastFrameBackground">
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.Toast"
android:textColor="@color/bright_foreground_dark"
android:shadowColor="#BB000000"
android:shadowRadius="2.75"
/>
</LinearLayout>
自定义View
当然,添加view,限制太大,还是自定义来的实在。
Toast toast = Toast.makeText(MainActivity.this, "欢迎光临阿东的博客", Toast.LENGTH_LONG);
LinearLayout toastView = (LinearLayout) LayoutInflater.from(MainActivity.this).inflate(R.layout.toast_view, null);
toast.setView(toastView);
toast.show();
子线程中执行
有的情况下我们可能需要Toast在子线程中执行,但是Toast内部用到了handler(看到有人有疑问,这只用到了Looper,并没有用到handler,那请你往里看看Toast的源码,TN类中是有使用handler的),大家知道handler必须依靠looper传递消息,所以必须在Toast前调用Looper.prepare();来注册当前Thread的looper。在Toast之后调用Looper.loop();让looper开始工作。如果有人有这样的疑问,我平时用的Toast也没有用到Looper啊,那是因为大多数情况下,Toast都是在主线程中使用,主线程中默认是开启looper的。
Thread thread = new Thread(new Runnable(){
@Override
public void run(){
Looper.prepare();
Toast.makeText(getActivity(), "欢迎来到阿东的博客", Toast.LENGTH_SHORT).show();
Looper.loop();
}
});
thread.start();
本想在本文把Toast的源码分析给大家,但是限于篇幅,还是分开写了。
想要看源码分析的话,请移步 《Android:Toast源码分析》