Interpolator (插值器)

我们在写动画的时候为了达到某种效果往往需要设置插值器,用来真实的模拟生活中的场景。

Interpolator (插值器)被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。

结构图:

常见的插值器:

AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速

AccelerateInterpolator  在动画开始的地方速率改变比较慢,然后开始加速

AnticipateInterpolator 开始的时候向后然后向前甩

AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值

BounceInterpolator   动画结束的时候弹起

CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线

DecelerateInterpolator 在动画开始的地方快然后慢

LinearInterpolator   以常量速率改变

OvershootInterpolator    向前甩一定值后再回到原来位置

如果上面的插值器不满足你的要求,你可以自定义插值器。

我们看一个效果

这里我自定义了一个插值器,实现匀速的转动

public class MyInterpolator extends LinearInterpolator {
	private float factor;

	public MyInterpolator() {
		this.factor = 0.15f;
	}

	@Override
	public float getInterpolation(float input) {
		return (float) (Math.pow(2, -10 * input)
				* Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1);
	}
}

接下来我们要说说Android属性动画的估值器。

TypeEvaluator(估值器)

TypeEvaluator(估值器):ValueAnimator.ofObject()函数来做动画效果的时候就会用到,作用是估算我们动画执行到什么程度,什么时间执行什么动画的一个类。估值器用到了TypeEvaluator这个接口:

public interface TypeEvaluator<t> {

    /**
     * @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);

}

这里有三个函数:fraction: 表示当前这段数值变化值得比例,startValue:表示当前这段数值变化的开始值,endValue: 表示当前这段数据变化的结束值。

估值器在哪里用得到呢,很多地方,举一个简单的例子,如用属性动画执行帧动画效果。

那么估值器是怎么工作的呢,我们来看下ValueAnimator的源码,其中在KeyframeSet类里有这么一个方法,这就是估值器工作的地方

public Object getValue(float fraction) {
        // Special-case optimization for the common case of only two keyframes
        if (mNumKeyframes == 2) {
            if (mInterpolator != null) {
                fraction = mInterpolator.getInterpolation(fraction);
            }
            return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
                    mLastKeyframe.getValue());
        }
        if (fraction <= 0f) {
            final Keyframe nextKeyframe = mKeyframes.get(1);
            final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
            if (interpolator != null) {
                fraction = interpolator.getInterpolation(fraction);
            }
            final float prevFraction = mFirstKeyframe.getFraction();
            float intervalFraction = (fraction - prevFraction) /
                (nextKeyframe.getFraction() - prevFraction);
            return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
                    nextKeyframe.getValue());
        } else if (fraction >= 1f) {
            final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
            final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
            if (interpolator != null) {
                fraction = interpolator.getInterpolation(fraction);
            }
            final float prevFraction = prevKeyframe.getFraction();
            float intervalFraction = (fraction - prevFraction) /
                (mLastKeyframe.getFraction() - prevFraction);
            return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
                    mLastKeyframe.getValue());
        }
        Keyframe prevKeyframe = mFirstKeyframe;
        for (int i = 1; i < mNumKeyframes; ++i) {
            Keyframe nextKeyframe = mKeyframes.get(i);
            if (fraction < nextKeyframe.getFraction()) {
                final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
                final float prevFraction = prevKeyframe.getFraction();
                float intervalFraction = (fraction - prevFraction) /
                    (nextKeyframe.getFraction() - prevFraction);
                // Apply interpolator on the proportional duration.
                if (interpolator != null) {
                    intervalFraction = interpolator.getInterpolation(intervalFraction);
                }
                return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
                        nextKeyframe.getValue());
            }
            prevKeyframe = nextKeyframe;
        }
        // shouldn't reach here
        return mLastKeyframe.getValue();
    }

在这之前有一个方法:

 void calculateValue(float fraction) {
        Object value = mKeyframes.getValue(fraction);
        mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
    }

调用到了getValue(),得到的值放在了mAnimatedValue里面,要通过PropertyValuesHolder类的getAnimatedValue()函数来得这个值
而这个函数在ValusAnimator中有调用。

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

Android系统内置了很多的估值器:

如下几种估值器 ArgbEvaluator, FloatArrayEvaluator, FloatEvaluator, IntArrayEvaluator, IntEvaluator, PointFEvaluator, RectEvaluator。

当然我们也可以自定义估值器,比我我们自定义一个实现字符从A_Z变化的估值器。

public class CalEvaluator implements TypeEvaluator<character> {

    @Override
    public Character evaluate(float fraction, Character startValue, Character endValue) {
        int startInt = (int) startValue;
        int endInt = (int) endValue;
        int cur = (int) (startInt + fraction * (endInt - startInt));
        return (char) cur;
    }
}

代码链接:点击打开链接

android动画之interpolator和typeEvaluator用法详解的更多相关文章

  1. Android GLSurfaceView用法详解(二)

    输入如何处理       若是开发一个交互型的应用(如游戏),通常需要子类化 GLSurfaceView,由此可以获取输入事件.下面有个例子: java代码: package eoe.ClearTes ...

  2. Android Fragment用法详解(2)--动态添加Fragment

    在上一篇文章<Android Fragment用法详解(1)--静态使用Fragment>我们讲解了Fragment的最简单的用法.这次我们来说一说Fragment复杂一丢丢的用法.在代码 ...

  3. CSS3的@keyframes用法详解:

    CSS3的@keyframes用法详解:此属性与animation属性是密切相关的,关于animation属性可以参阅CSS3的animation属性用法详解一章节. 一.基本知识:keyframes ...

  4. 1:CSS中一些@规则的用法小结 2: @media用法详解

    第一篇文章:@用法小结 第二篇文章:@media用法 第一篇文章:@用法小结 这篇文章主要介绍了CSS中一些@规则的用法小结,是CSS入门学习中的基础知识,需要的朋友可以参考下     at-rule ...

  5. Android ADB命令教程二——ADB命令详解

    Android ADB命令教程二——ADB命令详解 转载▼ 原文链接:http://www.tbk.ren/article/249.html       我们使用 adb -h 来看看,adb命令里面 ...

  6. Android进阶笔记:Messenger源码详解

    Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...

  7. Android逆向之旅---SO(ELF)文件格式详解(转)

    第一.前言 从今天开始我们正式开始Android的逆向之旅,关于逆向的相关知识,想必大家都不陌生了,逆向领域是一个充满挑战和神秘的领域.作为一名Android开发者,每个人都想去探索这个领域,因为一旦 ...

  8. Vue1.0用法详解

    Vue.js 不支持 IE8 及其以下版本,因为 Vue.js 使用了 IE8 不能实现的 ECMAScript 5 特性. 开发环境部署 可参考使用 vue+webpack. 基本用法 1 2 3 ...

  9. Android消息传递之EventBus 3.0使用详解

    前言: 前面两篇不仅学习了子线程与UI主线程之间的通信方式,也学习了如何实现组件之间通信,基于前面的知识我们今天来分析一下EventBus是如何管理事件总线的,EventBus到底是不是最佳方案?学习 ...

随机推荐

  1. 聊聊jstack的工作原理

    实现一个jstack 在聊Jstack得工作原理前呢,不如让我们先写一个简单的jstack玩玩.不用怕,很简单的,就几行代码的事,看: public class MyJstack { public s ...

  2. Node.js 多进程

    我们都知道 Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的系统上创建多个子进程,从而提高性能. 每个子进程总是带有三个流对象:child.st ...

  3. Java程序员的现代RPC指南

    Java程序员的现代RPC指南 1.前言 1.1 RPC框架简介 最早接触RPC还是初学Java时,直接用Socket API传东西好麻烦.于是发现了JDK直接支持的RMI,然后就用得不亦乐乎,各种大 ...

  4. java 里面保留字volatile及其与synchronized的区别

           锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility).互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议, ...

  5. Android Multimedia框架总结(十六)Camera2框架之openCamera及session过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52942533 前言:前一篇介绍了 ...

  6. JAVA面向对象-----包机制

    JAVA面向对象-–包机制 问题: 当定义了多个类的时候,可能会发生类名的重复问题. 在java中采用包机制处理开发者定义的类名冲突问题. 怎么使用java的包机制呢? 1.使用package 关键字 ...

  7. RxJava操作符(08-条件和布尔操作)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51671826 本文出自:[openXu的博客] 目录: All Amb Contains D ...

  8. Html书写规范,基本标签使用

    一.html简介1.html是什么Html是用来描述网页的一种语言.(1)HTML 指的是超文本标记语言 (Hyper Text Markup Language)(2)HTML 不是一种编程语言,而是 ...

  9. tomcat启动批处理——setclasspath.bat

    除了上面两个批处理,还有一个比较重要的脚本,即是setclasspath.bat,它主要负责寻找.检查JAVA_HOME和JRE_HOME两个变量. ************************* ...

  10. Java提升篇之反射的原理

    Java提升篇之反射的原理 1.构造方法的反射 import java.lang.reflect.Constructor; public class ReflectConstructor { publ ...