好吧,知識來源於實踐。最近項目有一個功能,要在全局範圍內實現提示功能,最後採用了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源碼分析》