先上大料:
View 动画 Animation 运行原理解析
Android动画原理分析
看完以上两篇文章,基本上就可以理清补间动画的实现原理了.
基本流程如下:
1,使用View.startAnimation()开启一个动画,在这个方法里面初始化了animation,并且执行了invalidate方法,这个是进入视图绘制流程的起点.
2,一旦执行了view的invalidate,那么就进入了整个视图树的遍历,最终走到ViewRootImpl,执行performTraversals方法,这个方法又会去执行子视图的三大绘制流程.
3,其中在view的draw(三个参数)方法中,会执行到view的applyLegacyAnimation方法.
4,view的applyLegacyAnimation中,使用view的animation变量,执行animation的getTransformation(其中一个参数是父view的transformation变量)方法.
5,animation的getTransformation主要做两个事情,传进一个父view的childTransformation视图变换矩阵(实际上是子view的,只是不知道为什么要存放在父view中),得到一个动画是否完成的boolean返回值. 在这个方法里面执行了Animation的applyTransformation方法,这个方法具体下沉到子类中来实现,比如在子类ScaleAnimation中实现是这样的:
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float sx = 1.0f;
float sy = 1.0f;
float scale = getScaleFactor();
if (mFromX != 1.0f || mToX != 1.0f) {
sx = mFromX + ((mToX - mFromX) * interpolatedTime);
}
if (mFromY != 1.0f || mToY != 1.0f) {
sy = mFromY + ((mToY - mFromY) * interpolatedTime);
}
if (mPivotX == 0 && mPivotY == 0) {
t.getMatrix().setScale(sx, sy);
} else {
t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
}
}
主要是根据第一个参数插值计算器计算出来的当前动画执行的进度,改变第二个参数transformation的值,记得这个值是父view的成员变量.这个值的具体用法,其实是用来和view的bitmap(是canvas)进行矩阵运算得到一个新的画布局域,也就是最终会根据这个运算得到一个新的视图,这也就是动画的真正原理,改变canvas画布里的bitmap(错误).https://blog.csdn.net/startfromweb/article/details/7644405
6,接着上面的计算,如果动画还要继续,那么getTransformation会返回true,回到view的applyLegacyAnimation中,其中有个判断:
private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
Animation a, boolean scalingRequired) {
Transformation invalidationTransform;
final int flags = parent.mGroupFlags;
final boolean initialized = a.isInitialized();
if (!initialized) {
a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
onAnimationStart();
}
final Transformation t = parent.getChildTransformation();
boolean more = a.getTransformation(drawingTime, t, 1f); // 在这里
if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
if (parent.mInvalidationTransformation == null) {
parent.mInvalidationTransformation = new Transformation();
}
invalidationTransform = parent.mInvalidationTransformation;
a.getTransformation(drawingTime, invalidationTransform, 1f);
} else {
invalidationTransform = t;
}
if (more) { // 这个值为true的话
if (!a.willChangeBounds()) {
if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) ==
ViewGroup.FLAG_OPTIMIZE_INVALIDATE) {
parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED;
} else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) {
// The child need to draw an animation, potentially offscreen, so
// make sure we do not cancel invalidate requests
parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
parent.invalidate(mLeft, mTop, mRight, mBottom);
}
} else {
if (parent.mInvalidateRegion == null) {
parent.mInvalidateRegion = new RectF();
}
final RectF region = parent.mInvalidateRegion;
a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
invalidationTransform);
// The child need to draw an animation, potentially offscreen, so
// make sure we do not cancel invalidate requests
parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
final int left = mLeft + (int) region.left;
final int top = mTop + (int) region.top;
parent.invalidate(left, top, left + (int) (region.width() + .5f),
top + (int) (region.height() + .5f)); // 又重新执行了invalidate
}
}
return more;
}
也就是当为true的情况,又会执行view的invalidate方法,那么就又进入了从1开始的流程中.这也就是为什么只启动一次,动画却一直会执行,视图会一直被更新,直到完成动画为止的原因了.
其实这个过程中,也就是不断的执行view的invalidate,通过Choreograher不断的安排执行view的绘制流程,在view的draw方法中,计算view的canvas变换矩阵.
所以这也就解释了,为什么补间动画只是改变view的视觉,他本来也就是仅仅改变了view的canvas中的bitmap(区域)而已.