属性动画,插值器,估值器

早期Android只有补间动画和帧动画,为了满足各种各样的动画效果,Android推出了属性动画。

补间动画和帧动画

帧动画
帧动画,我们从字面意思来理解,帧:就是影像动画中最小单位的单幅影像画面,相当于电影胶片上的每一格镜头。 一帧就是一副静止的画面,连续的帧就形成动画,如电视图象等。简单点说就是类似幻灯片播放的那种效果,因此帧动画的本质就是将一张张的图片,通过代码对这些图片进行连续的活动(这样就形成了动画)。

补间动画
即Tween动画或View动画, 通过对View的内容进行一系列的图形变换 (包括平移、缩放、旋转、改变透明度)来实现动画效果。动画效果的定义可以采用XML来做也可以采用编码来做。
所谓补间,就是确定2个帧,让计算机帮你计算帧之间的其他帧 ;如位移动画,我们只需要确定位置开始和结束这两个关键帧,计算机帮我们计算动画运行期间其他帧,让位移平缓地进行。

属性动画

一个View有位置,宽度,长度,颜色等各个属性,假如我们需要在手机每一帧都改变其值,就需要属性动画平缓地改变这些属性值;属性动画不仅仅用于View,也可以用任何对象,
属性动画的Animator 有两个

  • ValueAnimator 值动画
  • ObjectAnimator 对象动画

ObjectAnimator 继承ValueAnimator ,封装一些公共操作,如果只是对View进行简单处理,可以用它,少写一些代码。

ValueAnimator 值动画
要每一帧改变VIew的属性,我们需要通过一个计算机,帮我们计算每一帧的值,和每一帧回调给我们,然后我们去设置view的属性;

如下,ValueAnimator设置动画时长1.6s,并且设置从1到100的变化,在通过插值器和估值器的计算后,addUpdateListener将会在每一帧返回值,以60HZ为例,第二帧就会在16毫秒后得到值1,当然如果是120HZ,会在8毫秒得到值0.5;

    private void simple() {
        ValueAnimator mValueAnimator = ValueAnimator.ofObject(new FloatEvaluator(), 0, 100);
        mValueAnimator.setDuration(1600);
        mValueAnimator.addUpdateListener(animation -> {
            float color = (int) animation.getAnimatedValue();
            mView.setTranslationX(color);
        });
        mValueAnimator.start();
    }

scroller滑动动画与ValueAnimator 属性动画有点类似,但是scroller滑动动画无法设置插值器,所以没法做变速过度,scroller滑动动画用于滑动初始点和结束点频繁变化的情况,如手指跟随。

ObjectAnimator 值动画
很多的时候我们都懒得去自己写监听,然后去设置属性,于是谷歌帮我们写了 ObjectAnimator ,ObjectAnimator 继承 ValueAnimator,在动画过程中帮我们设置每一帧的属性(如位移),当然我们也可以自定义继承ValueAnimator自己写一个属性动画类

    private void simple2() {
        ObjectAnimator mValueAnimator = ObjectAnimator.ofFloat(mView, "translationX", 0f, 100f);
        mValueAnimator.setDuration(1600);
        mValueAnimator.start();
    }

上面ObjectAnimator 和ValueAnimator 都是实现一模一样的效果,通过使用用封装好的ObjectAnimator ,我们就可以少写很多代码,

多个动画同时执行
补间动画可以多个动画同时执行,属性也可以,参考多个属性动画合成

插值器

插值器其实就是计算进度的一个接口或实现类,根据时间流逝的比例,来得出属性值变化的比例
自定义插值器继承TimeInterpolator ,首先我们看接口定义

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

从方法参数可以得知,入参input是0到1.0;我们可以理解为百分比进度,告诉我们动画已经进行到什么时候了,如果是3秒动画,入参0.5,就是告诉我们已经进行了1.5秒了;但是有的时候我们需要做曲线变化,我们就需要重写getInterpolation方法,注意的是虽然入参范围是0~1,但是返回值可以在0 ~ 1范围外,比如一些弹性动画在后面的时候会谈到实际位置之外。

以一个线性差值器为例

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolator {
    public float getInterpolation(float input) {
        return input;
    }
}

我们可以看到getInterpolation直接返回input,因为线性插值器不需要做曲线处理,所以直接入参值了;
android默认帮我们写很多插值器
插值器

估值器

插值器在返回进度值后就要算出具体的属性值了;
自定义插值器继承TypeEvaluator ,首先我们看接口定义

public interface TypeEvaluator<T> {

    /**
     * This function returns the result of linearly interpolating the start and end values, with
     * <code>fraction</code> representing the proportion between the start and end values. The
     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
     * and <code>t</code> is <code>fraction</code>.
     *
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start value.
     * @param endValue   The end value.
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public T evaluate(float fraction, T startValue, T endValue);

}

就是在给出当前进度和初始值和结束值,来计算属性值,Android里面默认提供了如下几种估值器

  • ArgbEvaluator
  • FloatArrayEvaluator
  • FloatEvaluator
  • IntArrayEvaluator
  • IntEvaluator
  • PointFEvaluator
  • RectEvaluator

下面是IntEvaluator整形估值器源码

public class IntEvaluator implements TypeEvaluator<Integer> {
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}

实际上就是线性计算进度,比如在进度0.5的时候,就计算返回开始值和结束值中间的值;
我自定义使用线性插值和Int估值器,打印如下,实际上插值器的返回结果就是估值的一个入参。

getInterpolation 0.0
evaluate fraction:0.0 s:-16711936 e:-65536
getInterpolation 0.0
evaluate fraction:0.0 s:-16711936 e:-65536
getInterpolation 0.0056666667
evaluate fraction:0.0056666667 s:-16711936 e:-65536
getInterpolation 0.011
evaluate fraction:0.011 s:-16711936 e:-65536

感觉好像针对线性变换,重写插值器和估值器都可以,但是估值器往往自身就会一些数学计算在里面,计算起来不是很方便。而且有的估值器,估值起来不是很简单,比如做颜色变换的动画,从蓝色变成绿色,如果此时插值器返回当前进度是0.5(动画执行到一半),那么估值器应该返回一个什么颜色呢,插值器只返回一个当前进度;查看ArgbEvaluator估值器,我们可以清楚看到其处理逻辑。

public class ArgbEvaluator implements TypeEvaluator {
    /**
     * This function returns the calculated in-between value for a color
     * given integers that represent the start and end values in the four
     * bytes of the 32-bit int. Each channel is separately linearly interpolated
     * and the resulting calculated values are recombined into the return value.
     *
     * @param fraction The fraction from the starting to the ending values
     * @param startValue A 32-bit int value representing colors in the
     * separate bytes of the parameter
     * @param endValue A 32-bit int value representing colors in the
     * separate bytes of the parameter
     * @return A value that is calculated to be the linearly interpolated
     * result, derived by separating the start and end values into separate
     * color channels and interpolating each one separately, recombining the
     * resulting values in the same way.
     */
    public Object evaluate(float fraction, Object startValue, Object endValue) {
        int startInt = (Integer) startValue;
        float startA = ((startInt >> 24) & 0xff) / 255.0f;
        float startR = ((startInt >> 16) & 0xff) / 255.0f;
        float startG = ((startInt >>  8) & 0xff) / 255.0f;
        float startB = ( startInt        & 0xff) / 255.0f;

        int endInt = (Integer) endValue;
        float endA = ((endInt >> 24) & 0xff) / 255.0f;
        float endR = ((endInt >> 16) & 0xff) / 255.0f;
        float endG = ((endInt >>  8) & 0xff) / 255.0f;
        float endB = ( endInt        & 0xff) / 255.0f;

        // convert from sRGB to linear
        startR = (float) Math.pow(startR, 2.2);
        startG = (float) Math.pow(startG, 2.2);
        startB = (float) Math.pow(startB, 2.2);

        endR = (float) Math.pow(endR, 2.2);
        endG = (float) Math.pow(endG, 2.2);
        endB = (float) Math.pow(endB, 2.2);

        // compute the interpolated color in linear space
        float a = startA + fraction * (endA - startA);
        float r = startR + fraction * (endR - startR);
        float g = startG + fraction * (endG - startG);
        float b = startB + fraction * (endB - startB);

        // convert back to sRGB in the [0..255] range
        a = a * 255.0f;
        r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
        g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
        b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;

        return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
    }
}

分析上面代码,通过5个步骤估值器计算出此时应该显示的颜色:

  1. 首先计算出初始颜色和结束颜色的ARGB值
  2. 对各个ARGB值进行2.2的幂次处理
  3. 根据进度计算值ARGB值,
  4. 对各个ARGB值开2.2次方
  5. 重新组合成int型颜色值

总结

  • 属性动画是对属性做动画,属性要实现动画
  • 插值器就是反应属性变化的快慢,具体快慢的标准可以由插值器函数求导得到;
  • 估值器具体计算属性值,一般计算的方法就是start+(end-start)*fraction
  • 插值器的返回结果就是估值的入参
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值