认识动画(2)-interpolator插值器

概述

Interpolator属性是一个Animation类的一个XML属性,所以alpha,scale,rotate,translate,set都会继承得到这个属性.Interpolator被译为插值器,其实就是一个管理动画播放变化的一个属性.系统自带了一些插值器会让动画在播放过程中有更多的展示形式.

Interpolator的系统值

  • AccelerateDecelerateInterpolator 在动画开始与介绍的地方速率改变比较慢,在中间的时候加速
  • AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速
  • AnticipateInterpolator 开始的时候向后然后向前甩
  • AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
  • BounceInterpolator 动画结束的时候弹起
  • CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
  • DecelerateInterpolator 在动画开始的地方快然后慢
  • LinearInterpolator 以常量速率改变
  • OvershootInterpolator 向前甩一定值后再回到原来位置
    效果图示:


    image.png

Interpolator的代码使用

ScaleAnimation interpolateScaleAnim=new ScaleAnimation(0.0f,1.4f,0.0f,1.4f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);  
interpolateScaleAnim.setInterpolator(new BounceInterpolator());  
interpolateScaleAnim.setDuration(3000); 

Interpolator的XML文件使用

<?xml version="1.0" encoding="utf-8"?>  
<scale xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"  
    android:fromXScale="0.0"  
    android:toXScale="1.4"  
    android:fromYScale="0.0"  
    android:toYScale="1.4"  
    android:pivotX="50%"  
    android:pivotY="50%"  
    android:duration="700"   
    android:fillAfter="true"  
/>

自定义插值器

  1. 自定义插值器一般用于属性动画,所以我们首先看看,属性动画的简单使用代码段:
ValueAnimator animator = ValueAnimator.ofInt(0,600);  
  
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
    }  
});  
animator.setDuration(1000);  
animator.setEvaluator(new IntEvaluator());  
animator.setInterpolator(new BounceInterpolator());  
animator.start();  

我们可以看出,ValueAnimator的原理是通过监听数值变化进度,来实时改变View的属性从而达到动画的效果,而onAnimationUpdate所得到的动画进度,就来自Interpolator(插值器)

  1. 让我们先看看系统的插值器是怎么定义的:
public class LinearInterpolator implements Interpolator {  
  
    public LinearInterpolator() {  
    }  
  
    public LinearInterpolator(Context context, AttributeSet attrs) {  
    }  
  
    public float getInterpolation(float input) {  
        return input;  
    }  
}  
public interface Interpolator extends TimeInterpolator {  
}  

LinearINterpolator实现了Interpolator接口则直接继承自TimeInterpolator,而且并没有添加任何其他的方法.
让我们再看看TimeInterpolator接口做了什么?

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

我们可以看到,它里面只有一个函数float getInterpolation(float input);我们来看看这个方法是干嘛的.
参数input:参数是一个float类型的值,它的取值范围是0-1,表示动画的进度,取0时表示动画刚开始,即1表示动画刚结束,
返回值:表示当前要显示的参数,取值也可以超过1也可以小于0,超过1代表超过目标值,小于0表示小于开始位置.

Evaluator

概述

不是要讲插值器,这个Evaluator是什么东西?别急我们先看看下面的图:


image

这幅图讲述了从定义动画的数字区间到通过AnimationUpdateListener中得到当前动画所对应的数值的整个过程.下面我们对这4个步骤具体讲解一下:

  1. ofInt(0,400)表示指定动画的数字区间,是从0-400运动.
  2. 加速器:上面我们说了,动画开始后,通过加速器会返回当前的动画进度所对应的数字进度,但这个数字进度是百分制的,以小数表示,如0.2
  3. Evaluator:我们知道我们通过监听器拿到的是当前动画所对应的数值,而不是百分制的进度.那么就必须有一个地方会根据当前的数字进度,将其转换为对应的数值,这个地方就是Evaluator;Evaluator就是将加速器返回的数字进度转成对应数字的数字值.也就是下面公式:
当前的值 = 100 + (400 - 100)* 显示进度  
  1. 监听器:我们通过在AnimatorUpdateListener监听器使用animation.getAnimatedValue()函数拿到Evaluator中返回的值.
    所以说Evaluator就是一个计算器.

各种Evaluator

首先,加速器返回的都是小数值,表示的是当前动画的数值进度.无论是利用ofFloat()还是利用ofInt()定义的动画都是适用的.因为无论什么动画,它的进度必然都在0到1之间,0表示没开始,1表示已经结束,对于任何动画都是适用的.
但是Evaluator不一样,我们知道Evaluator是根据加速器返回的小数进度转换成当前数值进度所对应的值,那么问题就来了,如果我们使用ofInt来定义动画,得到的必然是int型,如果使用ofFloat来定义动画,得到的必然是Float型.每种定义方式使用的Evaluator必然是不同的,所以我们使用animator.setEvaluator()来设置Evaluator.具体代码如下:

<embed id="ZeroClipboardMovie_9" src="https://csdnimg.cn/public/highlighter/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="16" height="16" name="ZeroClipboardMovie_9" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=9&amp;width=16&amp;height=16" wmode="transparent" style="box-sizing: border-box;"> 

1.  ValueAnimator animator = ValueAnimator.ofInt(0,600);  

3.  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
4.  @Override  
5.  public void onAnimationUpdate(ValueAnimator animation) {  
6.  int curValue = (int)animation.getAnimatedValue();  
7.  tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
8.  }  
9.  });  
10.  animator.setDuration(1000);  
11.  animator.setEvaluator(new IntEvaluator());  
12.  animator.setInterpolator(new BounceInterpolator());  
13.  animator.start();

这时候就有人问了,之前我们直接使用ofInt()或者ofFloat定义动画也不会有问题啊?因为onInt和onFloat都是系统直接提供的函数,所以在使用时都会有默认的加速器和Evaluator来使用,不指定则使用默认的;对于Evaluator而言,ofInt()的默认Evaluator是IntEvaluator,ofFloat()的默认Evaluator是FloatEvaluator.
我们已经弄清楚Evaluator是干什么的了,接下来我们就以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));  
    }  
}  

我们可以看到在IntEvaluator中只有一条函数(int)(startInt + fraction * (endValue - startInt));其中fraction就是加速器返回值,startInt代表动画起始值,endValue代表动画结束值.这两个值由ofInt传入.这个公式整个所做的工作就是上面提到的

当前的值 = 100 + (400 - 100)* 显示进度  

自定义Evalutor

上面我们看了IntEvaluator的代码,我们仿照IntEvaluator的实现方法,我们自定义一个MyEvalutor,首先实现了TypeEvaluator接口:

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

我们看到这里使用了泛型,利用泛型我们可以自定义函数evaluate(float fraction, Integer startValue, Integer endValue)返回的类型,而在该方法内加入我们所需要的计算逻辑,从而制定我们需要的计算器.
如果我们需要输出一个倒序播放动画效果,只需要在evaluate方法中写入

 return (int) (endValue - fraction * (endValue - startInt));  

ArgbEvalutor

上面我们讲了IntEvaluator和FloatEvalutor,其实在android.animation包下,还有一个Evaluator叫ArgbEvalutor.
ArgbEvalutor是用来做颜色过渡转换的,可能是开发人员贴心的害我我们不太懂颜色怎么变换.来看代码:

public class ArgbEvaluator implements TypeEvaluator {  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        int startInt = (Integer) startValue;  
        int startA = (startInt >> 24);  
        int startR = (startInt >> 16) & 0xff;  
        int startG = (startInt >> 8) & 0xff;  
        int startB = startInt & 0xff;  
  
        int endInt = (Integer) endValue;  
        int endA = (endInt >> 24);  
        int endR = (endInt >> 16) & 0xff;  
        int endG = (endInt >> 8) & 0xff;  
        int endB = endInt & 0xff;  
  
        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |  
                (int)((startR + (int)(fraction * (endR - startR))) << 16) |  
                (int)((startG + (int)(fraction * (endG - startG))) << 8) |  
                (int)((startB + (int)(fraction * (endB - startB))));  
    }  
}  

我们这里关注两个地方,第一:返回类型是int类型,这说明我们可以用ofInt来初始化数值范围,第二:颜色值包括A,R,G,B四个值,每个值是8位所以用16进制表示一个颜色应该是0xffff0000(纯红色)
下面我们就使用一下ArgbEvaluator.

ValueAnimator animator = ValueAnimator.ofInt(0xffffff00,0xff0000ff);  
animator.setEvaluator(new ArgbEvaluator());  
animator.setDuration(3000);  
  
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.setBackgroundColor(curValue);  
  
    }  
});  
  
animator.start(); 

文章来自
http://blog.csdn.net/harvic880925/article/details/50546884

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容