您的位置:首页 > 其它

Toast自定义动画

2015-12-11 00:00 162 查看
摘要: 利用反射机制为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也是可以的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: