Toast自定义动画

上篇我讲了自定义Toast和不重复显示Toast,后来我在想官方Toast只有一个淡入淡出的,要自定义Taost动画该怎样做了。

首先来看Toast的源码:

构造函数如下:

    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这个类

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类只是去设置这个类的属性。大家来看

 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给我们的强大的反射机制。下面我们来看看该怎样处理:

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属性

Object mTN = null;
			mTN = getField(toast, "mTN");
Object mParams = getField(mTN, "mParams");
params.windowAnimations = styleId;

到此Toast自定义动画就算完成了,当然也有其他的方法,可以将Toast的源码整理,自己写一个Toast也是可以的。

转载于:https://my.oschina.net/u/579493/blog/542750

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值