浅析android动画绘制流程

应用开发中常会用到动画,我们也会经常用到动画(帧动画,补间动画,属性动画),但是可能很多人都不知道动画在什么地方绘制,怎么绘制的?知道这些后我们才能更加得心应手去使用它。

一, 动画基本组件
(1),Animation 动画定义,包含动画相关配置信息(开始时间,执行间隔,重复等等), 用到插间器Interpolator, Transfromation动画转化状态
(2)Interpolator   插间器:用于定义控制动画的变化,是否平缓,加速,减速等
(3) Transformation  动画转化状态, 结合插间器计算的当前状态的值,产生当次动画实际需要的转化结果(包含Matrix, 以及alpa等)。

二,动画绘制流程

 说明:在子视图本身加载动画的时候,我们应该发现,动画的作用范围是依赖父视图的,因此动画实际是在父视图容器内绘制。

下面进入正题贴图:

动画绘制分两个步骤:

1, 如何分发到animation

(1)通过 view.startAnimation调用动画

    public void startAnimation(Animation animation) {
        animation.setStartTime(Animation.START_ON_FIRST_FRAME);
        setAnimation(animation);
        invalidateParentCaches();
        invalidate(true);
    }

做了两件事,第一件清除父视图的缓存,让父视图绘制,调用自身局部刷新。(invalidate局部刷新会最终调用viewroot去分发,最终会遍历视图层级,绘制指定区域。而清除父视图缓存则让父视图在遍历过程支持重新创建绘制,这也就是说明动画绘制实际是依赖父视图内部绘制)

2 )绘制分发必然会走到 draw 方法,而父视图在处理时会 dipatchDraw 分发给子视图做进一步绘制。最终调到子视图 draw(canvas parent, drawTime) ,最终我们发现 drawAnimation(Parent...) 。返回 more 则判断是否需要继续执行动画,
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated;
        boolean more = false;
       parent.mChildTransformation.clear

        Transformation transformToApply = null;
   final Animation a = getAnimation();
        if (a != null) {
            more = drawAnimation(parent, drawingTime, a, scalingRequired);
    ..return more
}
2 Animation 执行

  private boolean drawAnimation(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();
        }

        boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f);
        if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
            if (parent.mInvalidationTransformation == null) {
                parent.mInvalidationTransformation = new Transformation();
            }
            invalidationTransform = parent.mInvalidationTransformation;
            a.getTransformation(drawingTime, invalidationTransform, 1f);
        } else {
            invalidationTransform = parent.mChildTransformation;
        }

        if (more) {
            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));
            }
        }
        return more;
    }

主要是这样的:首先会通过Animation.getTransformation(outTransform..)将当前时刻需要的动画转化信息获取,  而当前转化信息包含Matrix变化,以及alpa透明度。 Transformation获取的过程依赖 Interpolator插间器(内部计算动画变化趋势)确定。并且记录在 parent.mChildTransformation
后续Canvas根据transformation进行绘制。


猜你喜欢

转载自blog.csdn.net/u011098381/article/details/79564098