最近項目裏面需要一個Toast可以實現自由控制顯示的時間,但是android原生態的Toast顯示時間只有Length與Short兩種,不能夠滿足項目的需求。在網上查找了下實現方式,發現那些實現方法不怎麼好,自己特意從android源碼裏面把系統的Toast獨立出來,自定義一個自己的Toast類,實現了項目需求,並且在最後提供一個例子,介紹該Toast的使用方法。具體代碼如下:
Toast.java:
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
public class Toast {
static final String TAG = "Toast";
static final boolean localLOGV = false;
public static final int LENGTH_SHORT = 0;
public static final int LENGTH_LONG = 1;
final Context mContext;
final TN mTN;
View mNextView;
public Toast(Context context) {
mContext = context;
mTN = new TN();
mTN.mY = context.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
}
public void show() {
if (mNextView == null) {
throw new RuntimeException("setView must have been called");
}
TN tn = mTN;
tn.mNextView = mNextView;
mTN.show();
}
public boolean isShowing(){
return mTN.mIsShowing;
}
public void cancel() {
mTN.hide();
}
public void setView(View view) {
mNextView = view;
}
public View getView() {
return mNextView;
}
public void setMargin(float horizontalMargin, float verticalMargin) {
mTN.mHorizontalMargin = horizontalMargin;
mTN.mVerticalMargin = verticalMargin;
}
public float getHorizontalMargin() {
return mTN.mHorizontalMargin;
}
public float getVerticalMargin() {
return mTN.mVerticalMargin;
}
public void setGravity(int gravity, int xOffset, int yOffset) {
mTN.mGravity = gravity;
mTN.mX = xOffset;
mTN.mY = yOffset;
}
public int getGravity() {
return mTN.mGravity;
}
public int getXOffset() {
return mTN.mX;
}
public int getYOffset() {
return mTN.mY;
}
public static Toast makeText(Context context, CharSequence text) {
Toast result = new Toast(context);
LayoutInflater inflate = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(R.id.message);
tv.setText(text);
result.mNextView = v;
return result;
}
public static Toast makeText(Context context, int resId)throws Resources.NotFoundException {
return makeText(context, context.getResources().getText(resId));
}
public void setText(int resId) {
setText(mContext.getText(resId));
}
public void setText(CharSequence s) {
if (mNextView == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
TextView tv = (TextView) mNextView.findViewById(R.id.message);
if (tv == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
tv.setText(s);
}
private static class TN {
public boolean mIsShowing=false;
final Runnable mShow = new Runnable() {
@Override
public void run() {
handleShow();
mIsShowing=true;
}
};
final Runnable mHide = new Runnable() {
@Override
public void run() {
handleHide();
// Don't do this in handleHide() because it is also invoked by handleShow()
mIsShowing=false;
mNextView = null;
}
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
final Handler mHandler = new Handler();
int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
int mX, mY;
float mHorizontalMargin;
float mVerticalMargin;
View mView;
View mNextView;
WindowManager mWM;
TN() {
final WindowManager.LayoutParams params = mParams;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
// params.format = PixelFormat.OPAQUE;
params.windowAnimations = R.style.Animation_Toast;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("Toast");
}
public void show() {
if (localLOGV) Log.v(TAG, "SHOW: " + this);
mHandler.post(mShow);
}
public void hide() {
if (localLOGV) Log.v(TAG, "HIDE: " + this);
mHandler.post(mHide);
}
public void handleShow() {
if (mView != mNextView) {
handleHide();
mView = mNextView;
mWM = (WindowManager)mView.getContext().getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
final int gravity = mGravity;
mParams.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
mParams.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
mParams.verticalWeight = 1.0f;
}
mParams.x = mX;
mParams.y = mY;
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
if (mView.getParent() != null) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
mWM.addView(mView, mParams);
}
}
public void handleHide() {
if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
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) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
mView = null;
}
}
}
}
Toast.java類結束
下面是該類引用的一些資源文件:
1佈局文件/res/layout/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="@drawable/toast_frame"
>
<TextView
android:id="@+id/message"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
android:textAppearance="@style/small"
android:textColor="@color/bright_foreground_dark"
android:shadowColor="#BB000000"
android:shadowRadius="2.75"
/>
</LinearLayout>
2動畫文件/res/anim,裏面有兩個動畫文件
(1) toast_enter.xml,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/decelerate_quad"
android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="@android:integer/config_longAnimTime" />
(2) toast_exit.xml,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/decelerate_quad"
android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="@android:integer/config_longAnimTime" />
3 Toast Y軸的偏移量/res/values/dimens.xml,代碼如下:
<dimen name="toast_y_offset">64dip</dimen>
4 Toast的Style設置/res/values/styles.xml,代碼如下:
<style name="Animation" />
<style name="Animation.Toast">
<item name="android:windowEnterAnimation">@anim/toast_enter</item>
<item name="android:windowExitAnimation">@anim/toast_exit</item>-->
</style>
5佈局中的背景圖片toast_frame在圖片上傳哪裏,第一次使用博客,不曉得傳成功沒有,
如果沒有成功,可以自己找一個圖片作爲背景。系統圖片是.9.png的圖片。
6 例子:
Toast toast;
Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case 0:
toast=Toast.makeText(context,"自己寫的toast,可以自由控制顯示時間");
toast.show();
break;
case 1:
if(toast!=null){
toast.cancel();
}
break;
default:
break;
}
}
};
mHandler.sendEmptyMessage(0);
new Thread(){
public void run(){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mHandler.sendEmptyMessage(1);
}
}.start();