Android动画原理

2020-05-08  本文已影响0人  杨殿生

动画分类

补间动画

旋转、位移、透明度、缩放

属性动画

同样的属性动画也可以做到对View进行缩放、移动、旋转以及改变透明度;除此以外,它还能改变对象的某个属性。
ObjectAnimator.ofFloat()
ValueAnimator.start()

ObjectAnimator继承于ValueAnimator

 public void start() {
    start(false);
}
private void start(boolean playBackwards) {
    if (Looper.myLooper() == null) {
        throw new AndroidRuntimeException("Animators may only be run on Looper threads");
    }
    //省略部分代码...
    //为动画添加回调
    addAnimationCallback(0);
    //判断动画开始时间是否需要延迟
    if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
        startAnimation();
        if (mSeekFraction == -1) {
            setCurrentPlayTime(0);
        } else {
            setCurrentFraction(mSeekFraction);
        }
    }
}

addAnimationCallback(0);

这里调用了AnimationHandler类的addAnimationFrameCallback(),最终会调用doAnimationFrame方法

 private void doAnimationFrame(long frameTime) {
        long currentTime = SystemClock.uptimeMillis();
        final int size = mAnimationCallbacks.size();
        for (int i = 0; i < size; i++) {
            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
            if (callback == null) {
                continue;
            }
            if (isCallbackDue(callback, currentTime)) {
                callback.doAnimationFrame(frameTime);
                if (mCommitCallbacks.contains(callback)) {
                    getProvider().postCommitCallback(new Runnable() {
                        @Override
                        public void run() {
                            commitAnimationFrame(callback, getProvider().getFrameTime());
                        }
                    });
                }
            }
        }
        cleanUpList();
    }

将一个callback丢到Choreographer中,当下一个Vsync信号来时执行doAnimationFrame()

/**
     * Callbacks that receives notifications for animation timing and frame commit timing.
     */
    interface AnimationFrameCallback {

        boolean doAnimationFrame(long frameTime);
        void commitAnimationFrame(long frameTime);
    }

doAnimationFrame()中会执行到animateValue()

void animateValue(float fraction) {
        fraction = mInterpolator.getInterpolation(fraction);
        mCurrentFraction = fraction;
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].calculateValue(fraction);
        }
        if (mUpdateListeners != null) {
            int numListeners = mUpdateListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                mUpdateListeners.get(i).onAnimationUpdate(this);
            }
        }
    }

mInterpolator就是插值器TimeInterpolator、TimeInterpolator接口提供了一个方法getInterpolation()获取当前属性随时间变化的百分比

public interface TimeInterpolator {
    float getInterpolation(float input);
}

mValues[i].calculateValue(fraction);会调用估值器,将插值器计算出的值作为输入,计算出要变化的值设置给属性

public interface TypeEvaluator<T> {
    public T evaluate(float fraction, T startValue, T endValue);

}

startAnimation()

startAnimation()会调用ininAnimation()方法而ObjectAnimation重写了该方法

void initAnimation() {
    if (!mInitialized) {
        final Object target = getTarget();
        if (target != null) {
            final int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].setupSetterAndGetter(target);
            }
        }
        super.initAnimation();
    }
}

mValues为PropertyValuesHolder类型,从这可以看出调用了PropertyValuesHolder的setupSetterAndGetter方法,这个方法中查找了相对应属性的set/get方法。最终会调用 getPropertyFunction()方来获取相应的方法,若通过反射没有获取到相应的set/get方法时就会抛出 NoSuchMethodException异常

private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
    // TODO: faster implementation...
    Method returnVal = null;
    //prefix表示set或get,然后在通过getMethodName()方法拼接出相应的方法名
    String methodName = getMethodName(prefix, mPropertyName);
    Class args[] = null;
    //省略部分代码
     returnVal = targetClass.getMethod(methodName, args);
            return returnVal;
     //省略部分代码       
}

因为我们需要对View的translationX属性进行设置,所以通过这里可以看出我们设置属性时是通过View.setTranslationX()方法来设置的。

Choreographer

Choreographer是动画原理的一个核心,搞明白动画工作原理之前我们需要先了解Choreographer工作过程;
Choreographer工作过程简单描述如下:在Choreographer对象中有四条链表,分别保存着待处理的输入事件,待处理的动画事件,待处理的View绘制事件、待处理的post到Choreographer中事件,Android系统每隔16.7ms发出VSYNC信号,Choreographer.FrameDisplayEventReceiver收到信号后调用onVsync方法,最终会调用Choreographer.doFrame()方法,在doFrame方法中处理输入事件、动画事件、View绘制、post到Choreographer中的FrameCallback;我们可以使用Choreographer#postFrameCallback设置callback与Choreographer交互,设置的FrameCallCack(doFrame方法)会在下一个frame被渲染时触发(即下一个VSYNC到来时执行);Choreographer更多内容请参考Android Choreographer 源码分析
Android动画原理简单描述:将View的一次大的属性变化拆分为多次小的属性变化,在每次VSYNC信号到来时,根据当前时间和插值器来计算当前View属性的值,然后给View设置该属性值,直到动画执行完毕。其中Choreographer将动画拆分成一次次小的属性变化,Choreographer是动画的指挥者。理想情况下,属性刷新次数(动画拆分为多次小的属性变化) = 动画执行时间/16.7ms 。

参考
Android动画原理探究

上一篇下一篇

猜你喜欢

热点阅读