上篇我講了自定義Toast和不重複顯示Toast,後來我在想官方Toast只有一個淡入淡出的,要自定義Taost動畫該怎樣作了。java
首先來看Toast的源碼:
android
構造函數以下:app
public Toast(Context context) { mContext = context; mTN = new TN(); mTN.mY = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.toast_y_offset); mTN.mGravity = context.getResources().getInteger( com.android.internal.R.integer.config_toastDefaultGravity); }
你們看到沒有這裏有一個 TN 的對象mTN,接着來看看TN這個類
ide
private static class TN extends ITransientNotification.Stub { final Runnable mShow = new Runnable() { @Override public void run() { handleShow(); } }; final Runnable mHide = new Runnable() { @Override public void run() { handleHide(); // Don't do this in handleHide() because it is also invoked by handleShow() mNextView = null; } }; private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); final Handler mHandler = new Handler(); int mGravity; int mX, mY; float mHorizontalMargin; float mVerticalMargin; View mView; View mNextView; WindowManager mWM; TN() { // XXX This should be changed to use a Dialog, with a Theme.Toast // defined that sets up the layout params appropriately. final WindowManager.LayoutParams params = mParams; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.windowAnimations = com.android.internal.R.style.Animation_Toast; params.type = WindowManager.LayoutParams.TYPE_TOAST; params.setTitle("Toast"); params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; } /** * schedule handleShow into the right thread */ @Override public void show() { if (localLOGV) Log.v(TAG, "SHOW: " + this); mHandler.post(mShow); } /** * schedule handleHide into the right thread */ @Override public void hide() { if (localLOGV) Log.v(TAG, "HIDE: " + this); mHandler.post(mHide); } public void handleShow() { } private void trySendAccessibilityEvent() {} public void handleHide() {} } }
代碼不少這裏刪掉了幾個函數的代碼,你們主要看這幾個屬性函數
int mGravity; //控制Toast的顯示的方式居上居中仍是居下等 int mX, mY; //Toast x y的偏移量 float mHorizontalMargin; float mVerticalMargin;
你們注意到沒有實際上Toast的全部控制的屬性都是封裝在這個內部類中,外部類也就是Toast類只是去設置這個類的屬性。你們來看post
public void setGravity(int gravity, int xOffset, int yOffset) { mTN.mGravity = gravity; mTN.mX = xOffset; mTN.mY = yOffset; }
上面的函數是設置Toast顯示的位置我相信咱們也常常調用,實際上這都是設置TN這個類的屬性。下面咱們來找找咱們須要的動畫屬性:
動畫
final WindowManager.LayoutParams params = mParams; params.windowAnimations = com.android.internal.R.style.Animation_Toast;
看到沒有在這裏,可是問題來了Toast沒有暴露出咱們能夠動態設置此屬性的方法,而且此類是mTn對象是defualt類型的變量也就是說咱們應用想要直接經過mTN對象來設置params的windowAnimations的屬性是不可能的。那這樣咱們豈不是一籌莫展了,顯然不是咱們還有一個java給咱們的強大的反射機制。下面咱們來看看該怎樣處理:this
import java.lang.reflect.Field; import android.content.Context; import android.view.WindowManager; import android.widget.Toast; /** * 自定義動畫的Toast * @author ziyao * */ public class MyToast extends Toast { public MyToast(Context context) { super(context); } /** * 調用有動畫的Toast * @param context * @param text * @param duration * @param 自定義的動畫id * @return */ public static Toast makeTextAnim(Context context, CharSequence text, int duration,int styleId) { Toast toast = makeText(context, text, duration); toast.setText(text); toast.setDuration(duration); try { Object mTN = null; mTN = getField(toast, "mTN"); if (mTN != null) { Object mParams = getField(mTN, "mParams"); if (mParams != null && mParams instanceof WindowManager.LayoutParams) { WindowManager.LayoutParams params = (WindowManager.LayoutParams) mParams; params.windowAnimations = styleId; } } } catch (Exception e) { e.printStackTrace(); } return toast; } /** * 反射字段 * @param object 要反射的對象 * @param fieldName 要反射的字段名稱 * @return * @throws NoSuchFieldException * @throws IllegalAccessException */ private static Object getField(Object object, String fieldName) throws NoSuchFieldException, IllegalAccessException { Field field = object.getClass().getDeclaredField(fieldName); if (field != null) { field.setAccessible(true); return field.get(object); } return null; } }
首先經過反射機制得到Toast中的mTN對象而後再反射獲得mTN中的mParams屬性最後設置mParams.windowAnimations屬性code
Object mTN = null; mTN = getField(toast, "mTN");
Object mParams = getField(mTN, "mParams");
params.windowAnimations = styleId;
到此Toast自定義動畫就算完成了,固然也有其餘的方法,能夠將Toast的源碼整理,本身寫一個Toast也是能夠的。orm