属性动画2:ValueAnimator高级进阶(一)

参考博客:
[1] 启舰: 自定义控件三部曲之动画篇(五)——ValueAnimator高级进阶(一)
[2]郭霖:Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法
[3] Developers :ValueAnimator
[4] Android开发艺术探索
[5] Carson_Ho: Android 属性动画:这是一篇很详细的 属性动画 总结&攻略
[6] 常用插值器源码分析:https://my.oschina.net/banxi/blog/135633

1. 概述

前面一篇属性动画1:基础知识和ValueAnimator写完,我对属性动画基础知识和ValueAnimator的简单用法有了一些了解。要想把属性动画吃透,我感觉需要更加深入的学习。现在,就从ValueAnimator的高级进阶开始,继续攻克我的属性动画。
ValueAnimator的高级进阶主要涉及到插值器(Interpolator)和计算器(Evaluator)的使用。

我们知道ValueAnimator是对值的动画,它在整个动画持续时间内按一定规则平滑计算出一系列某种类型的中间值。这个规则就可以理解为插值器,对某种类型的值的计算由类型计算器负责。

在上一篇文章中我们已经提到过:

在动画执行过程中,ValueAnimator根据动画总时长duration和动画已经执行的时间,计算出一个在0到1之间的时间流逝小数(elapsed fraction),这个小数(elapsed fraction)表示动画已经执行的时间百分比,0表示0%,1表示100%。

当ValueAnimator开始计算时间流逝小数(elapsed fraction),它就会调用时间插值器TimeInterpolator,插值器内部定义了关于时间(时间流逝小数:elapsed fraction)的函数,这个内部的时间函数通过对时间流逝小数(elapsed fraction)的计算,得到一个插值小数(interpolated fraction)。

计算了插值小数(interpolated fraction),ValueAnimator就会调用合适的TypeEvaluator,根据插值小数(interpolated fraction)、开始值和结束值计算出当前的属性值。

2. 插值器

插值器,也叫加速器,有关插值器的源码和曲线,推荐一篇比较好的博客https://my.oschina.net/banxi/blog/135633以作参考,这篇博客既专业又易懂。

但到底什么是插值器?插值器在ValueAnimator中是怎么使用的呢?时间插值器(TimeInterpolator)顾名思义,它一定与时间有关。事实上插值器就是一个关于时间的函数,它通过对时间流逝小数(或时间流逝百分比)进行一定的函数计算,获得一个个插值小数,这个小数可以代表动画值变化(增加或减少)的百分比。说白了就是时间流逝百分比与属性值变化百分比之间的对应关系,或者函数关系。插值器决定了动画值随着时间流逝如何变化,是线性变化(均匀变化)还是非线性变化(如先加速后减速)。

如从参考博客https://my.oschina.net/banxi/blog/135633中取出加速减速插值器的源码和曲线图,如下:

AccelerateDecelerateInterpolator 加速减速插值器
源代码如下:

/**
 * An interpolator where the rate of change starts and ends slowly but
 * accelerates through the middle.
 */
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
    }
}

根据getInterpolation()方法可以得出其变化曲线如下:
加速减速插值器函数曲线

源码中的getInterpolation()方法的参数input其实就是时间流逝小数。

2.1 简单源码分析

上一篇中,我们知道ValueAnimator默认插值器是加速减速插值器(AccelerateDecelerateInterpolator),从ValueAnimator的源码中可以看到:

ValueAnimator默认插值器

如果没有给动画设置插值器(加速器)就使用默认插值器。

插播一下,往下翻看ValueAnimator的源码发现,
属性动画默认duration
属性动画默认时长是300ms。

为ValueAnimator设置插值器,需要调用ValueAnimator的setInterpolator()方法,下面是ValueAnimator的setInterpolator()方法的源码:

/**
 * The time interpolator used in calculating the elapsed fraction of this animation. The
 * interpolator determines whether the animation runs with linear or non-linear motion,
 * such as acceleration and deceleration. The default value is
 * {@link android.view.animation.AccelerateDecelerateInterpolator}
 *
 * @param value the interpolator to be used by this animation. A value of <code>null</code>
 * will result in linear interpolation.
 */
@Override
public void setInterpolator(TimeInterpolator value) {
    if (value != null) {
        mInterpolator = value;
    } else {
        mInterpolator = new LinearInterpolator();
    }
}

setInterpolator()源码,我们知道:

  • 时间插值器用于对当前动画的时间流逝百分比进行计算。
  • 插值器决定了动画是按照线性运行还是按照非线性运行,比如加速或减速。
  • ValueAnimator默认插值器是加速加速插值器(AccelerateDecelerateInterpolator)。
  • setInterpolator()方法传一个空(null)值,会返回一个线性插值器

继续看ValueAnimator的源码,找到了下面这个方法——animateValue(),从这个方法的注释我们知道了它的作用:

  1. 此方法会在 每一个动画帧 伴随 时间流逝分数(elapsed fraction) 被调用。
  2. 此方法将时间流逝分数转变成一个插值分数,然后转变成一个动画值(通过计算器evaluator)。
  3. 该方法主要在动画更新过程中调动,但也在end()方法调用时调用来设置属性的终值。
  4. 该方法的参数是时间流逝分数(elapsed fraction)。
/**
 * This method is called with the elapsed fraction of the animation during every
 * animation frame. This function turns the elapsed fraction into an interpolated fraction
 * and then into an animated value (from the evaluator). The function is called mostly during
 * animation updates, but it is also called when the <code>end()</code>
 * function is called, to set the final value on the property.
 *
 * <p>Overrides of this method must call the superclass to perform the calculation
 * of the animated value.</p>
 *
 * @param fraction The elapsed fraction of the animation.
 */
@CallSuper
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);
        }
    }
}

上面animateValue()方法的源码中我们找到了这行代码
fraction = mInterpolator.getInterpolation(fraction);
表示插值器调用getInterpolation(fraction)对时间流逝分数(elapsed fraction)进行计算,获得一个fraction,这个fraction就是插值分数(interpolated fraction)。
方法的最后,我们发现此方法遍历了UpdateListener集合,并调用了每一个UpdateListener(ValueAnimator.AnimatorUpdateListener)的onAnimationUpdate方法,并把ValueAnimator自己作为参数传了过去。

2.2 自定义插值器

自定以插值期之前,我们先看一下ValueAnimator默认的插值器源码是怎么实现的:
AccelerateDecelerateInterpolator

/**
 * An interpolator where the rate of change starts and ends slowly but
 * accelerates through the middle.
 */
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }

    @SuppressWarnings({"UnusedDeclaration"})
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
    }
}

BaseInterpolator

/**
 * An abstract class which is extended by default interpolators.
 */
abstract public class BaseInterpolator implements Interpolator {
    
    
    private int mChangingConfiguration;
    /**
     * @hide
     */
    public int getChangingConfiguration() {
    
    
        return mChangingConfiguration;
    }

    /**
     * @hide
     */
    void setChangingConfiguration(int changingConfiguration) {
    
    
        mChangingConfiguration = changingConfiguration;
    }
/**
 * An interpolator defines the rate of change of an animation. This allows
 * the basic animation effects (alpha, scale, translate, rotate) to be 
 * accelerated, decelerated, repeated, etc.
 */
public interface Interpolator extends TimeInterpolator {
    
    
    // A new interface, TimeInterpolator, was introduced for the new android.animation
    // package. This older Interpolator interface extends TimeInterpolator so that users of
    // the new Animator-based animations can use either the old Interpolator implementations or
    // new classes that implement TimeInterpolator directly.
}

从上面源码中我们看到AccelerateDecelerateInterpolator继承自BaseInterpolator,BaseInterpolator实现了Interpolator,而Interpolator继承自TimeInterpolator。下面我们直接看TimeInterpolator接口的源码:

/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

3.计算器

4. keyFrame–关键帧

猜你喜欢

转载自blog.csdn.net/wangxiaocheng16/article/details/75204968
今日推荐