Android 动画框架
View动画 (tween animation)
帧间动画(frmae animation)
属性动画 (Property Animation)
View 动画原理
以 AlphaAnimation 为例,AlphaAnimation new 以后,通常要调用View的startAnimation
startAnimation来执行动画:
alphaImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Animation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
alphaAnimation.setDuration(5000);
alphaImageView.startAnimation(alphaAnimation);
}
});
View#startAnimation 的具体方法:
/**
* Start the specified animation now.
*
* @param animation the animation to start now
*/
public void startAnimation(Animation animation) {
animation.setStartTime(Animation.START_ON_FIRST_FRAME);
setAnimation(animation);
invalidateParentCaches();
invalidate(true);
}
- 设置开始时间Animation.START_ON_FIRST_FRAME 其实是 -1;
- animation赋值 内部变量 mCurrentAnimation
- 调用 view 的invalidate(true),请求绘制重绘
回调postCallback
按照android 的View 绘制流程,invalideate 回调用到ViewRootImpl#invalidate -> ViewRootImpl#scheduleTraversals ->
Choreographer#postCallback
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
当 SVNC 信号到来时,mTraversalRunnable 会被回调, 进入View 的重绘流程。
- ViewRootImpl#TraversalRunnable#run->
- ViewRootImpl->doTraversal->
- ViewRootImpl#performTraversals->
- ViewRootImpl#performDraw->
- ViewRootImpl#draw->
- ViewRootImpl#drawSoftware->
- View#draw(Canvas canvas)->
- ViewGroup#dispatchDraw->
- ViewGroup#drawChild->
- View#draw(Canvas canvas, ViewGroup parent, long drawingTime)
draw Animation
View 动画的出现在第10步中,可以看到这行函数:
final Animation a = getAnimation();
在一开始startAnimation的时候,setAnimation, 现在get了,然后调用applyLegacyAnimation。
/**
* This method is called by ViewGroup.drawChild() to have each child view draw itself.
*
* This is where the View specializes rendering behavior based on layer type,
* and hardware acceleration.
*/
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
......
Transformation transformToApply = null;
boolean concatMatrix = false;
final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;
final Animation a = getAnimation();
if (a != null) {
more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
concatMatrix = a.willChangeTransformationMatrix();
if (concatMatrix) {
mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
}
transformToApply = parent.getChildTransformation();
} else {
......
}
......
float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha());
if (transformToApply != null
|| alpha < 1
|| !hasIdentityMatrix()
|| (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) {
if (transformToApply != null || !childHasIdentityMatrix) {
......
if (transformToApply != null) {
if (concatMatrix) {
if (drawingWithRenderNode) {
renderNode.setAnimationMatrix(transformToApply.getMatrix());
} else {
// Undo the scroll translation, apply the transformation matrix,
// then redo the scroll translate to get the correct result.
canvas.translate(-transX, -transY);
canvas.concat(transformToApply.getMatrix());
canvas.translate(transX, transY);
}
}
float transformAlpha = transformToApply.getAlpha();
if (transformAlpha < 1) {
alpha *= transformAlpha;
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
}
......
}
}
.......
if (a != null && !more) {
if (!hardwareAcceleratedCanvas && !a.getFillAfter()) {
onSetAlpha(255);
}
parent.finishAnimatingView(this, a);
}
if (more && hardwareAcceleratedCanvas) {
if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
// alpha animations should cause the child to recreate its display list
invalidate(true);
}
}
return more;
}
applyLegacyAnimation 函数
第一次进入 a.initialize 动画初始化。然后回调 onAnimationStart。
获取 parent 的ChildTransformation t, Transformation t = parent.getChildTransformation();然后对t 通过调用a.getTransformation 赋值。动画的API我们的主角终于出场了.applyLegacyAnimation 函数的结果是将计算后的Transformation 保存到parent.
/**
* Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
* case of an active Animation being run on the view.
*/
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;
}
......
draw(canvas);
return more;
}
继续回到draw 函数中:
transformToApply = parent.getChildTransformation();
获取 applyLegacyAnimation 计算后的Transformation,然后再
canvas.translate(-transX, -transY);
canvas.concat(transformToApply.getMatrix());
canvas.translate(transX, transY);
对canvas 做矩阵变换,动画效果已经出来。最后 draw(canvas);
对draw函数的总结就是:
- 获取Animation getAnimation()
- 调用 applyLegacyAnimation 根据根据动画运行时间调用Animation getTransformation 获取Transformation,然后将结果保存到parent.
- 调用 parent.getChildTransformation(); 获取保存的Transformation。
- 根据得到的Transformation 对canvas 的Matrix 做矩阵变换
- 调用draw(canvas) 绘制。
- 可以看出View动画没有改变View的坐标属性,只是在draw 的时候做了形变。