android_动画框架

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值