Toast自定義動畫

上篇我講了自定義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

相關文章
相關標籤/搜索