声明:本篇文章部分内容来自《Android开发艺术探索》。

我们都知道对于属性动画可以对某个属性做动画,而 插值器(TimeInterpolator)和 估值器(TypeEvaluator)在其中扮演了重要角色,下面先了解下 TimeInterpolator TypeEvaluator

TimeInterpolator(时间插值器):

作用:根据时间流逝的百分比计算出当前属性值改变的百分比。

系统已有的插值器:

  • LinearInterpolator(线性插值器):匀速动画。

  • AccelerateDecelerateInterpolator(加速减速插值器):动画两头慢,中间快。

  • DecelerateInterpolator(减速插值器):动画越来越慢。

TypeEvaluator(类型估值算法,即估值器):

 

作用:根据当前属性改变的百分比来计算改变后的属性值。

系统已有的估值器:

  • IntEvaluator:针对整型属性

  • FloatEvaluator:针对浮点型属性

  • ArgbEvaluator:针对Color属性

那么 TimeInterpolator和 TypeEvaluator 是怎么协同工作的呢?

它们是实现 非匀速动画 的重要手段。属性动画是对属性做动画,属性要实现动画,首先由TimeInterpolator(插值器)根据时间流逝的百分比计算出当前属性值改变的百分比,并且 插值器 将这个百分比返回,这个时候 插值器 的工作就完成了。

比如 插值器 返回的值是0.5,很显然我们要的不是0.5,而是当前属性的值,即当前属性变成了什么值,这就需要 估值器 根据当前属性改变的百分比来计算改变后的属性值,根据这个属性值,我们就可以设置当前属性的值了。

源码分析

上面的理论知识可能比较抽象,下面根据一个实例结合系统源码来分析一下:

下图表示一个匀速动画,采用了线性插值器和整型估值算法,在40ms内,View的x属性实现从0到40的变换。

由于动画的默认刷新率为10ms/帧,所以该动画将分为5帧进行。

当动画进行到第三帧的时候,(x=20,t=20ms)当时间 t=20ms 的时候,时间流逝的百分比是0.5(20/40=0.5),即时间过了一半。这个百分比不是我们最终想要的,我们关心的是x的变化,那么x应该变化多少呢?插值器和估值算法就起作用了。拿 线性插值器 来说,线性插值器是实现 匀速动画 的,先看一下线性插值器 的源码:

很显然,线性插值器 的返回值和输入值一样(看getInterpolation方法),因此 t=20ms 时 插值器 返回的值是 0.5,这意味着 x属性的改变是0.5。这个时候 插值器 的工作已经完成了,插值器 的工作就是根据时间流逝的百分比计算出当前属性值改变的百分比。

我们得到了当前属性改变的百分比是0.5,即50%。下一步就是要算出x具体变为了什么值,这个时候 估值算法 就起作用了,它的作用就是根据当前属性改变的百分比来计算改变后的属性值。我们先看看系统提供的 整型估值算法 的源码:

上述代码中的 evaluate方法 的三个参数分别表示 估值小数(fraction)开始值(startValue)和 结束值(endValue)。对于我们的这个例子就是 0.5,0和40。我们将这三个值代入求值,即:0+0.5*(40 - 0)=20。没错,这就是当 t=20ms 时 x=20 的由来。

其实对于 插值器和估值器 来说,除了系统提供的外,我们还可以自定义。实现方式也很简单,因为插值器和估值器都是一个接口,且内部都只有一个方法,我们只要实现接口就可以了,就可以做出很多绚丽的动画了。其中,自定义插值器 需要实现 Interpolator或者TimeInterpolator自定义估值器 需要实现TypeEvaluator

但是一般来说,插值器 使用系统的就足够了,估值器 自定义的可能会多一些,另外就是如果要对其他类型(非Int丶float丶color)做动画,必须自定义类型估值算法。

代码演示(一)

在这里我们用两种方式实现抛物线轨迹,一种是 固定时间的抛物线,一种是 固定长度的抛物线

球按照抛物线轨迹运行1.5秒(参照鸿洋大神的抛物线效果):

首先分析一下实现过程:

要实现抛物线的效果,水平方向200px/s垂直方向加速度200px/s*s,你会发现我们只需要知道时间的变化,就可以求出某刻小球的水平位移(即x)和 数值位移(即y)。那么公式就是:x = 200t ; y=200t²

但是还有一个问题就是,我们要同时记录两个值并进行 估值算法,所以我们可以创建一个Point类 来保存这两个值。前面我们使用过 ValueAnimator 的 ofFloat() 和 ofInt()方法,分别用于对 浮点型 和 整型 的数据进行动画操作的,但实际上 ValueAnimator 中还有一个ofObject() 方法,是用于对任意对象进行动画操作的。

相比于浮点型或整型数据,对象的动画操作明显要更复杂一些,因为系统将完全无法知道如何从初始对象过度到结束对象,因此这个时候我们就需要实现一个自己的 TypeEvaluator 来告知系统如何进行过度。这里我们要过度的对象就是 Point对象

首先,定义一个 Point类,如下所示:

 /**
* 保存小球坐标的类
*/
public class Point {
float x;
float y; public Point(){} public Point(float x,float y){
this.x = x;
this.y = y;
}
}

Point 类非常简单,x和y两个变量用于记录坐标的位置,并且提供了两个构造方法。

接下来 自定义估值算法,来告知系统如何实现初始对象到结束对象的过度(对于 插值器 来说,我们就使用 系统的线性插值器 即可,无须自定义):

对于自定义估值算法,你需要指定一个泛型,这里我们操作的是Point 对象,当我们指定Point 为泛型时,evaluate方法 的返回值也是Point ,并且startValue 和 endValue也是 Point 类型,这样就对了,在自定义估值算法中,我们就可以直接使用 Point 对象了。

但是你会发现一个问题就是,我们并没有用到 startValue 和 endValue,而是使用了一个写死的1.5f,因为没必要,我们的抛物线是与时间挂钩的,不用他们也是完全可以的,这样写的话,出来的效果就是:球运行1.5s的轨迹图。(下面我们还会有一个例子,它的自定义估值算法就是以startValue和endValue来计算的)。

布局很简单,一个 RelativeLayout 包含一个 显示小球的ImageView 以及一个 用于操控的Button。这里就不贴出了。

下面看 MainActivity 的代码:

通过代码发现,我们调用 ValueAnimator的ofObject() 方法来构建 ValueAnimator 的实例,这里需要注意的是,ofObject() 方法要求多传入一个 TypeEvaluator 参数,这里我们只需要传入刚才定义好的 MyTypeEvaluator 的实例就可以了。

还有我们设置了 1500ms 的持续时间,这里的 1500ms和自定义估值器里面的1.5f不是一回事,也就是说我们就算设置的是2000ms的持续时间,得到的小球运行轨迹是一样的,因为自定义估值器里面的 1.5f是写死的

运行效果:

我们发现小球确实是抛物线运行,但是仔细看代码你会发现,我们并没有指定小球的落点位置,即 Point对象的终止属性,那么小球落点的位置是哪里呢?其实我们可以算出来,即x=200*1.5=300;y=200*1.5*1.5=450。但是现在我们更换一下需求,要求小球刚好落在屏幕的右边缘,而不是求具体时间小球的轨迹。

小球呈抛物线轨迹运行到屏幕的右边缘(自己尝试的抛物线效果):

 

我们知道 y=ax^2 也是抛物线的一个公式,但是仔细看这个公式你会发现,它不是以t为基准了,而是y与x的关系,也就是说y的变化直接与x挂钩。并且对于 y=ax^2,我们知道a越小,开口越大,所以为了抛物线效果好看,我们此次使用的 a=0.001

要实现这个效果,其实可以 不用ofObject() 方法,也就是说不用自定义估值算法,直接 使用ofFloat() 也是可以实现的,即直接使用系统的估值器。我们可以为 x属性设置一个匀速动画,然后设置监听器来实现为x和y设置属性值。

代码如下:

运行效果:

确实,小球在碰到右边部就停止了,是我们想要的效果。

其实要实现抛物线效果方法应该还有很多。结合数学公式还可以做出很多效果,比如正选曲线运动等。

代码演示(二)

上面我们演示了抛物线效果,下面我们再来一个效果,这次我们要 自定义估值算法并且使用startValue和endValue参数 来做算法。

自定义估值算法:

代码如下:

理一下思路:

  1. 首先创建Point类用来保存坐标信息,Point对象即是我们要操作的对象 。

  2. 自定义估值算法 MyTypeEvaluator,并制定 泛型为Point类型,在 evaluate方法 中进行估值算法,为point对象的x和y赋值并将该对象返回。

  3. 在 MainActivity 中调用 ValueAnimator.ofObject() 方法获得 ValueAnimator 对象,并传入 自定义估值器对象 和 Point的初始对象与终止对象

  4. 为 ValueAnimator 对象设置 AnimatorUpdateListener 监听,在 onAnimationUpdate()中通过 Point point = (Point) animation.getAnimatedValue();即可获得在估值算法中返回的Point对象,并为小球设置新的x和y值。

运行效果如下:

没错,小球从(0,0)坐标运行到了(200,300)坐标,并按我们预想的轨迹运行。

Android属性动画:插值器与估值器的更多相关文章

  1. Android 动画:你真的会使用插值器与估值器吗?

    目录   目录 1. 插值器(Interpolator) 1.1 简介 定义:一个接口 作用:设置 属性值 从初始值过渡到结束值 的变化规律 如匀速.加速 & 减速 等等 即确定了 动画效果变 ...

  2. Android 属性动画 源码解析 深入了解其内部实现

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/42056859,本文出自:[张鸿洋的博客] 我参加了博客之星评选,如果你喜欢我的博 ...

  3. 【转】android 属性动画之 ObjectAnimator

    原文网址:http://blog.csdn.net/feiduclear_up/article/details/39255083 前面一篇博客讲解了 android 简单动画之 animtion,这里 ...

  4. Android属性动画之ValueAnimation

    ValueAnimation是ObjectAnimation类的父类,经过前几天的介绍,相信大家对ObjectAnimation有了 一定的认识,今天就为大家最后介绍一下ValueAnimation, ...

  5. Android属性动画完全解析(下)

    转载:http://blog.csdn.net/guolin_blog/article/details/44171115 大家好,欢迎继续回到Android属性动画完全解析.在上一篇文章当中我们学习了 ...

  6. Android属性动画完全解析(上)

    Android属性动画完全解析(上) 转载:http://blog.csdn.net/guolin_blog/article/details/43536355 在手机上去实现一些动画效果算是件比较炫酷 ...

  7. Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44171115 大家好,欢迎继续回到Android属性动画完全解析.在上一篇文章当中 ...

  8. 详解Android属性动画

    前面我们讲到的属性动画都是使用代码的定义方式:Android属性动画之ValueAnimator和Android属性动画之ObjectAnimator和AnimatorSet,下面我们再来看看使用XM ...

  9. Android属性动画之ValueAnimator的介绍

    之前两篇博客,介绍的是ObjectAnimator作用与某一个控件的某一个属性.但我们的ValueAnimator它本身并不会作用与任何一个属性,它本身也不会提供任何一种动画.它简单的来说,就是一个数 ...

随机推荐

  1. 解决后台json数据返回的字段需要替换的问题

    有时候后台json数据返回的字段含有“id”,也有可能是有时候为了减少代码的冗余,两页面之间只是数据模型个别属性的区别,所以这时候最好是用到模型属性的替换,用新的属性替换返回的json数据的字段.这里 ...

  2. NOIP2017滚粗记【上】

    Day0: NOIP前停课训练的最后一天,上午打了一场三题都见过的比赛,一窝人AK. 下午一群人在机房缓慢氧化,到了晚上因为比赛在我们学校打,所以所有的机房都断网了(百思不得其解为什么两个竞赛室也被断 ...

  3. POJ 2371

    #include<iostream> #include<stdio.h> #include<string> using namespace std; int com ...

  4. Cygwin安装配置

    1.下载安装Cygwin   我们可以到Cygwin的官方网站下载Cygwin的安装程序,地址是: http://www.cygwin.com/ 或者直接使用下载连接来下载安装程序,下载连接是: ht ...

  5. 页面滚动插件 better-scroll 的用法

    better-scroll 是一个页面滚动插件,用它可以很方便的实现下拉刷新,锚点滚动等功能. 实现原理:父容器固定高度,并设置 overflow:hidden,子元素超出父元素高度后将被隐藏,超出部 ...

  6. HUE配置文件hue.ini 的hdfs_clusters模块详解(图文详解)(分HA集群和非HA集群)

    不多说,直接上干货! 我的集群机器情况是 bigdatamaster(192.168.80.10).bigdataslave1(192.168.80.11)和bigdataslave2(192.168 ...

  7. 理解kubernetes环境的iptables

    node节点的iptables是由kube-proxy生成的,具体实现可以参见kube-proxy的代码 kube-proxy只修改了filter和nat表,它对iptables的链进行了扩充,自定义 ...

  8. Node.js之Express四

    Express提供的大部分功能是通过中间件函数完成的,这些中间件函数在Node.js收到请求的时点和发送响应的时点之间执行.Express的Connect模块提供了中间件框架,可以方便的在全局或路径级 ...

  9. java开学考试感想及代码

    上周四我们的第一节java课,王老师给我们进行啦开学考试,这也是上学期放假之前给我们约定好的 但是情况显然没有我想的那么好,其实我觉得这个atm系统比上届学生信息管理系统难的多,上届的话毕竟有小学期的 ...

  10. ionic中generate page后module.ts报错的解决办法

    此问题出现在Ionic官方将版本从2.2升级到Ionic3以上之后, 在项目中generate page时,自动创建的module.ts就报错,如下: 解决办法如下: 1)将IonicModule替换 ...