【Android】动画(Animation)原理简析

2021-12-13  本文已影响0人  littlefogcat

一、开始

调用View.startAnimation开始运行动画。

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

这个方法很简单,主要做了两件事:

  1. 将动画赋值给当前View的mCurrentAnimation变量;
  2. 标记当前的View需要重绘;

二、运行中

2.1 前期

在Choreographer接收到vsync信号后,回调给ViewRootImpl,开始刷新界面。
经过一系列的调用,最终,会进入到View的draw(Canvas canvas, ViewGroup parent, long drawingTime)方法中。
这个过程比较长,涉及到的类有Choreographer -> ViewRootImpl -> ThreadRenderer -> ViewGroup -> View。

2.2 View

View的draw(Canvas canvas, ViewGroup parent, long drawingTime)方法会调用applyLegacyAnimation方法,该方法又会调用Animation的getTransformation方法。

2.3 Animation

Animation.getTransformation中,会进行一系列的处理,将当前时间根据设置的插值器转换为插值时间,并最终调用applyTransformation方法。这是动画实现核心逻辑的地方。根据applyTransformation的具体实现,就可以完成动画在当前帧的动作。

applyTransformation接收2个参数,第一个是插值时间,相当于动画完成的百分比;第二个是一个Transformation对象,通过操作这个对象来实现动画。

例如,AlphaAnimation.applyTransformation方法实现如下:

    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float alpha = mFromAlpha;
        t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
    }

ScaleAnimation.applyTransformation方法实现如下:

    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);
        }
    }

三、结束

2.2 中的applyLegacyAnimation方法会返回一个boolean值,标记了动画是否还要继续执行。如果该值为false,表示动画需要结束。
如果标记需要结束动画,则View会执行parent.finishAnimatingView方法。在其父布局中,又会调用view.clearAnimation方法。也就是说,最终调用的是View的clearAnimation方法。在其中,会将mCurrentAnimation变量置为null。

四、总结

  1. Choreographer类会监听设备的vsync信号,在每一帧刷新的时候,收到回调。
  2. 当收到回调后,Choreographer会通知ViewRootImpl刷新视图树。
  3. 刷新视图树会调用View.draw(canvas, parent, time)方法。
  4. View.draw(canvas, parent, time)最终会调用Animation.getTransformation方法。
  5. AnimationgetTransformation中会调用applyTransformation方法,Animation子类在其中完成动画的具体实现。
上一篇 下一篇

猜你喜欢

热点阅读