android_动画框架

来源:互联网 发布:一起走数据怎么作弊 编辑:程序博客网 时间:2024/06/05 20:32

Android 动画框架

动画API介绍

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 的重绘流程。

  1. ViewRootImpl#TraversalRunnable#run->
  2. ViewRootImpl->doTraversal->
  3. ViewRootImpl#performTraversals->
  4. ViewRootImpl#performDraw->
  5. ViewRootImpl#draw->
  6. ViewRootImpl#drawSoftware->
  7. View#draw(Canvas canvas)->
  8. ViewGroup#dispatchDraw->
  9. ViewGroup#drawChild->
  10. 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函数的总结就是:

  1. 获取Animation getAnimation()
  2. 调用 applyLegacyAnimation 根据根据动画运行时间调用Animation getTransformation 获取Transformation,然后将结果保存到parent.
  3. 调用 parent.getChildTransformation(); 获取保存的Transformation。
  4. 根据得到的Transformation 对canvas 的Matrix 做矩阵变换
  5. 调用draw(canvas) 绘制。
  6. 可以看出View动画没有改变View的坐标属性,只是在draw 的时候做了形变。
0 0
原创粉丝点击