补间动画(Tween animation)是通过在两个关键帧之间补充渐变的动画效果来实现的。
Android系统提供了四个补间动画的类,分别是AlphaAnimation、RotateAnimation、ScaleAnimation和TranslateAnimation,另外还有一个能够把多个动画组合起来的AnimationSet类,这些类都有一个共同的基类Animation。
Animation类官方文档:
https://developer.android.com/reference/android/view/animation/Animation.html
类图:
一、Animation介绍
Animation是一个抽象类,无法直接使用,通常使用的是它的直接子类。
public abstract class Animation implements Cloneable {
}
Animation类定义了一些与动画相关的变量,子类可以直接使用。
/**
* 一个动画周期的持续时间,以毫秒为单位。
*/
long mDuration;
/**
* 动画开始执行的延时时长。如果大于0,动画的执行时间为startTime+startOffset。
*/
long mStartOffset;
/**
* 设置为true时,将保持动画开始前的状态。默认值为true。
*/
boolean mFillBefore = true;
/**
* 设置为true时,将保持动画结束时的状态。默认值为false。
*/
boolean mFillAfter = false;
/**
* 设置为true时,将应用mFillBefore的值;否则,忽视mFillBefore的值。默认值为false。
*/
boolean mFillEnabled = false;
/**
* 动画重复的次数。
*/
int mRepeatCount = 0;
/**
* 动画的重复类型,取值为RESTART(从头播放)或REVERSE(倒序回放)。
*/
int mRepeatMode = RESTART;
/**
* 表示动画在执行期间,被设置动画的内容在Z轴上的顺序。
* 取值范围ZORDER_NORMAL(保持不动)、ZORDER_TOP(在所有其他内容的顶部)、ZORDER_BOTTOM(在所有其他内容的底部),默认为ZORDER_NORMAL
*/
private int mZAdjustment;
/**
* 动画的背景色。
*/
private int mBackgroundColor;
/**
* 如果设置为true,并且动画窗体有一个壁纸的话,那么动画只会应用给窗体,壁纸是静止不动的。默认值为false。
*/
private boolean mDetachWallpaper = false;
/**
* 插值器,用来修饰动画效果。
*/
Interpolator mInterpolator;
同时也有一些常量,用来给特定的变量赋值。
/**
* mRepeatCount设置为INFINITE,表示动画无限循环。
*/
public static final int INFINITE = -1;
/**
* mRepeatMode设置为RESTART,表示动画结束后从头开始执行。
*/
public static final int RESTART = 1;
/**
* mRepeatMode设置为REVERSE,表示动画结束后反过来执行。
*/
public static final int REVERSE = 2;
/**
* setStartTime()传入该值时,动画将在第一次调用getTransformation(long, Transformation)时开始执行。
*/
public static final int START_ON_FIRST_FRAME = -1;
/**
* 具体的坐标值。
*/
public static final int ABSOLUTE = 0;
/**
* 相对自身的坐标值。
*/
public static final int RELATIVE_TO_SELF = 1;
/**
* 相对父容器的坐标值。
*/
public static final int RELATIVE_TO_PARENT = 2;
/**
* mZAdjustment设置为ZORDER_NORMAL,表示内容在Z轴保持不动。
*/
public static final int ZORDER_NORMAL = 0;
/**
* mZAdjustment设置为ZORDER_TOP,表示内容的Z轴方向在所有其他内容的顶部。
*/
public static final int ZORDER_TOP = 1;
/**
* mZAdjustment设置为ZORDER_BOTTOM,表示内容的Z轴方向在所有其他内容的底部。
*/
public static final int ZORDER_BOTTOM = -1;
这些成员变量在构造方法中被初始化。
public Animation(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation);
setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0));
setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0));
setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled));
setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));
setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));
setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
a.recycle();
if (resID > 0) {
setInterpolator(context, resID);
}
ensureInterpolator();
}
上面的每一个成员变量都有与之对应的set方法和xml属性。以成员变量mDuration为例,它的set方法为setDuration(),xml属性为android:duration。
Animation类内部定义了动画的监听器AnimationListener,通过调用setAnimationListener()方法来设置监听器。
AnimationListener mListener;
/**
* 设置动画的监听
*/
public void setAnimationListener(AnimationListener listener) {
mListener = listener;
}
/**
* 动画的监听
*/
public static interface AnimationListener {
/**
* 动画开始时回调。
*/
void onAnimationStart(Animation animation);
/**
* 动画结束时回调。
* 但是当动画重复次数被设置为INFINITE的时候,该方法不会回调。
*/
void onAnimationEnd(Animation animation);
/**
* 动画重复时回调。
*/
void onAnimationRepeat(Animation animation);
}
Animation类是通过applyTransformation()方法来处理动画变化的过程。
protected void applyTransformation(float interpolatedTime, Transformation t) {
}
可以看到,在Animation类中applyTransformation()方法是空的,具体实现由它的四个子类来完成。每个动画实现类都重载了Animation类的applyTransformation()方法,该方法把一些属性组装成一个Transformation类,该方法会被getTransformation()方法调用。
在动画的执行过程中,会反复的调用applyTransformation()方法。每次调用参数interpolatedTime值都会变化,该参数从0.0递增为1.0,当该参数为1.0时表示动画结束。Transformation类封装了矩阵Matrix和透明度Alpha值,通过参数Transformation来设置Matrix和Alpha,实现各种效果。
如果我们需要实现自己的动画类,需要下面两个步骤:
(1).继承Animation类。
(2).实现applyTransformation()方法。
一、Animation执行过程
在启动动画时,一般是调用View类的startAnimation(anim)方法。
先从View类开始看起。
public void startAnimation(Animation animation) {
animation.setStartTime(Animation.START_ON_FIRST_FRAME);
setAnimation(animation);
invalidateParentCaches();
invalidate(true);
}
protected Animation mCurrentAnimation = null;
public void setAnimation(Animation animation) {
mCurrentAnimation = animation;
// other code ......
}
在startAnimation()方法内部,先调用setAnimation()方法给成员变量mCurrentAnimation赋值,然后它调用invalidate()来重绘自己。
接下来进入draw()方法。
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
// other code ......
final Animation a = getAnimation();
if (a != null) {
more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
}
// other code ......
}
public Animation getAnimation() {
return mCurrentAnimation;
}
private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
Animation a, boolean scalingRequired) {
// other code ......
boolean more = a.getTransformation(drawingTime, t, 1f);
// other code ......
}
在draw()方法内部调用了View类的applyLegacyAnimation(),而applyLegacyAnimation()内部又调用了Animation类的getTransformation(long,Transformation,float)方法。
再次回到Animation类中,会发现最终在getTransformation()方法中调用了applyTransformation()方法,实现各种动画效果。
public boolean getTransformation(long currentTime, Transformation outTransformation,
float scale) {
mScaleFactor = scale;
return getTransformation(currentTime, outTransformation);
}
public boolean getTransformation(long currentTime, Transformation outTransformation) {
// other code ......
applyTransformation(interpolatedTime, outTransformation);
// other code ......
}