Android动画机制总结笔记--属性动画PropertyAnimation篇之ValueAnimator

注意:本篇文章是本人阅读关于Android动画的文章所写下的总结,方便以后查阅,所有内容非原创,侵权删。

本篇文章内容来自于

  1. Android高级进阶 顾浩鑫
  2. Android自定义控件三部曲文章索引之动画篇

目录

4.属性动画PropertyAnimation(基类Animator)
--4.1 ValueAnimator
----4.1.1 ValueAnimator构造函数
----4.1.2 ValueAnimator常用方法
----4.1.3 ValueAnimator监听器(2种)
----4.1.4 ValueAnimator代码实现(5种)【3和5待补】
----4.1.5 首先理解interpolator和Evaluator的功能和关系
----4.1.6 interpolator插值器(系统+自定义)
----4.1.7 Evaluator(系统+自定义)
----4.1.8 ValueAnimator XML实现

4.属性动画PropertyAnimation(基类Animator)

一个完整的属性动画由两部分组成:
1.计算动画各个帧的相关属性值
2.将这些属性值设置给指定的对象

4.1 ValueAnimator(属性动画最重要的类)

ValueAnimator只实现了属性动画应该具备的两个功能的第一个,第二部分由开发者自行设置。
即ValueAnimator不会对控件做任何操作,我们可以给它设定从哪个值运动到哪个值,通过监听这些值的渐变过程来自己操作控件。

4.1.1 ValueAnimator构造函数

ValueAnimator的构造函数是空实现,一般使用静态工厂方法来实现实例化。

public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofArgb(int... values)
public static ValueAnimator ofFloat(float... values)
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)

参数类型都是可变参数长参数,所以我们可以传入任何数量的值;
传进去的值列表,就表示动画时的变化范围;
比如ofInt(2,90,45)就表示从数值2变化到数字90再变化到数字45;

4.1.2 ValueAnimator常用方法
//设置动画时长,单位是毫秒 
ValueAnimator setDuration(long duration)  
//获取ValueAnimator在运动时,当前运动点的值 
Object getAnimatedValue();  
//开始动画 
void start()  
//设置循环次数,设置为0表示不循环,设置为ValueAnimation.INFINITE表示无限循环。 
void setRepeatCount(int value)  
//设置循环模式 
//取值为ValueAnimation.RESTART时,表示正序重新开始,当取值为ValueAnimation.REVERSE表示倒序重新开始。 
void setRepeatMode(int value)  
//设置插值器
setInterpolator(xxxx)
//取消动画 
void cancel() 

// 延时多久时间开始,单位是毫秒  
public void setStartDelay(long startDelay)  
//完全克隆一个ValueAnimator实例,包括它所有的设置以及所有对监听器代码的处理 
public ValueAnimator clone()  
4.1.3 ValueAnimator监听器(2种)

监听器一:监听动画变化时的实时值

public static interface AnimatorUpdateListener {  
    void onAnimationUpdate(ValueAnimator animation);  
}  

//添加方法
public void addUpdateListener(AnimatorUpdateListener listener) 
//移除方法
public void removeUpdateListener(AnimatorUpdateListener listener);  
public void removeAllUpdateListeners();   

//===代码实现===
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());  
        }  
    }); 

监听器二:监听动画变化时四个状态

public static interface AnimatorListener {  
    void onAnimationStart(Animator animation);  
    void onAnimationEnd(Animator animation);  
    void onAnimationCancel(Animator animation);  
    void onAnimationRepeat(Animator animation);  
}  
//添加方法
public void addListener(AnimatorListener listener)   
//移除方法
void removeListener(AnimatorListener listener);  
void removeAllListeners();  

//===代码实现===
animator.addListener(new Animator.AnimatorListener() {  
        @Override  
        public void onAnimationStart(Animator animation) {  
            Log.d("xl","animation start");  
        }  
  
        @Override  
        public void onAnimationEnd(Animator animation) {  
            Log.d("xl","animation end");  
        }  
  
        @Override  
        public void onAnimationCancel(Animator animation) {  
            Log.d("xl","animation cancel");  
        }  
  
        @Override  
        public void onAnimationRepeat(Animator animation) {  
            Log.d("xl","animation repeat");  
        }  
    });
4.1.4 ValueAnimator代码实现(5种)
1⃣️ ofInt(只能传入Integer类型的值)
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 400);
valueAnimatorInt.setDuration(1000);

valueAnimatorInt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        int curValue = (int) animation.getAnimatedValue();
                        tvAnimPropertyValue.layout(curValue,curValue,curValue+tvAnimPropertyValue.getWidth(),curValue+tvAnimPropertyValue.getHeight());
                    }
                });

valueAnimatorInt.start();
2⃣️ ofFloat(只能传入Float类型的值)
ValueAnimator valueAnimatorFloat = ValueAnimator.ofFloat(0f, 400f, 50f, 300f);
valueAnimatorFloat.setDuration(3000);

valueAnimatorFloat.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float animatedValue = (float) animation.getAnimatedValue();
                        int curValue = (int) animatedValue;
                        tvAnimPropertyValue.layout(curValue,curValue,curValue+tvAnimPropertyValue.getWidth(),curValue+tvAnimPropertyValue.getHeight());
                    }
                });

valueAnimatorFloat.start();
3⃣️ ofArgb
4⃣️ ofObject(可以传进去任何类型的变量)

构造方法解释

public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values);  
/*两个参数,第一个是自定义的Evaluator,第二个是可变长参数,Object类型的;
为什么要强制传进去自定义的Evaluator?
Evaluator的作用是根据当前动画的显示进度,计算出当前进度下把对应的值。
既然Object对象是我们自定的,那必然从进度到值的转换过程也必须由我们来做,不然系统不知道要转成什么鬼。*/

实例

ValueAnimator valueAnimatorObject = ValueAnimator.ofObject(new CharEvaluator(), new Character('A'), new Character('Z'));
valueAnimatorObject.setDuration(10000);
valueAnimatorObject.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        char animatedValue = (char) animation.getAnimatedValue();
                        tvAnimPropertyValue.setText(String.valueOf(animatedValue));
                    }
                });
valueAnimatorObject.start();
public class CharEvaluator implements TypeEvaluator<Character> {
    @Override
    public Character evaluate(float fraction, Character startValue, Character endValue) {
        int startInt = (int)startValue;
        int endInt = (int)endValue;
        int curInt = (int)(startInt + fraction *(endInt - startInt));
        char result = (char) curInt;
        return result;
    }
}
5⃣️ ofPropertyValuesHolder

参考ObjectAnimator的ofPropertyValuesHolder的实现

4.1.5 首先理解interpolator和Evaluator的功能和关系

如果看完还是不懂就戳这

ValueAnimator anim = ValueAnimator.ofInt(100, 400);    
anim.setDuration(1000);    
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    
    @Override    
    public void onAnimationUpdate(ValueAnimator animation) {    
        float currentValue = (float) animation.getAnimatedValue();    
        Log.d("TAG", "cuurent value is " + currentValue);    
    }    
});    
anim.start(); 

在添加了AnimatorUpdateListener的监听以后,通过在监听函数中调用 animation.getAnimatedValue()就可以得到当前的值;
那当前的值是怎么来的呢?
当前的值 = 100 + (400 - 100)* 显示进度

  • 100和400就是我们设置的ofInt(100,400)中的值
  • 显示进度是通过interpolator得到 [interpolator将时间变化(0-1)转化成显示进度(0-1,但也可以大于1小于0)]
  • 而整个公式当前的值 = 100 + (400 - 100)* 显示进度是在Evaluator中计算的。

关系图如下


关系图
4.1.6 interpolator插值器

插值器用来将时间进度转换成显示进度

1.系统自带插值器
interpolator的系统值

意义如下:

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

使用

ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setInterpolator(new BounceInterpolator());
....
2.自定义插值器

先看看系统加速器LinearInterpolator的写法:

//以常量速率改变的加速器LinearInterpolator
public class LinearInterpolator implements Interpolator {  
  
    public LinearInterpolator() {  
    }  
  
    public LinearInterpolator(Context context, AttributeSet attrs) {  
    }  
  
    public float getInterpolation(float input) {  
        return input;  
    }  
}  

//接口Interpolator(LinearInterpolator实现了Interpolator接口)
public interface Interpolator extends TimeInterpolator {  
}  

//(Interpolator接口则直接继承自TimeInterpolator)
public interface TimeInterpolator {  
    float getInterpolation(float input);  
/*
  参数input:
  input参数是一个float类型,它取值范围是0到1,表示当前动画的时间进度(与我们的任何设置无关).
  取0时表示动画刚开始,取1时表示动画结束,取0.5时表示动画中间的位置,其它类推。
 
  返回值:
  表示当前实际想要显示的进度。取值可以超过1也可以小于0。
  超过1表示已经超过目标值,小于0表示小于开始位置。
 */
}  

从上面可以看到,LinearInterpolator在getInterpolation函数中,直接把input值返回,即以当前动画的进度做为动画的数值进度,这也就表示当前动画的数值进度与动画的时间进度一致,比如,如果当前动画进度为0,那动画的数值进度也是0,那如果动画进度为0.5,那动画的数值进度也是在0.5,当动画结束,动画的进度就变成1了,而动画的数值进度也是1了。

则自定义Interpolator

public class MyInterpolator implements Interpolator {
    @Override
    public float getInterpolation(float input) {
        return 1-input;
    }
}

使用

ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setInterpolator(new MyInterpolator());
...
4.1.7 Evaluator

Evaluator是根据加速器返回的小数进度转换成当前数值进度所对应的值。

1.系统自带Evaluator

Evaluator是专用的。
Evalutor一般来讲不能通用,会报强转错误,也就是说,只有在数值类型相同的情况下,Evalutor才能共用。

ofInt()对应的Evaluator类名叫IntEvaluator
ofFloat()对应的Evaluator类名叫FloatEvaluator
ofInt和ofFloat都是系统直接提供的函数,所以在使用时都会有默认的加速器和Evaluator来使用的,不指定则使用默认的;

ArgbEvalutor是用来做颜色值过渡转换的。可配合使用ofInt()

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

                    }
                });
valueAnimatorIntArgb.start();
2.自定义Evaluator

看看IntEvaluator内部是怎么实现:

public class IntEvaluator implements TypeEvaluator<Integer> {  
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
          /*
         其中fraction就是加速器中的返回值,表示当前动画的数值显示进度,百分制的小数表示。 
         startValue和endValue分别对应ofInt(int start,int end)中的start和end的数值;
         */
        int startInt = startValue;  
        return (int)(startInt + fraction * (endValue - startInt));  
        //也就是 当前的值 = 100 + (400 - 100)* 显示进度  
    }  
}  

自定义Evaluator

public class MyEvaluator implements TypeEvaluator<Integer> {
    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int) (200 + startInt + fraction * (endValue - startInt));
    }
}
3.使用
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setEvaluator(new IntEvaluator());
...
4.1.8 ValueAnimator XML实现

标签<animator />对应ValueAnimator

4.1.8.1 animator所有的字段及取值范围
<animator
    android:duration="int"
    android:valueFrom="float | int | color"
    android:valueTo="float | int | color"
    android:startOffset="int"
    android:repeatCount="int"
    android:repeatMode=["repeat" | "reverse"]
    android:valueType=["intType" | "floatType"]
    android:interpolator=["@android:interpolator/XXX"]/>

android:valueType:表示参数值类型,取值为intType和floatType;
与android:valueFrom、android:valueTo相对应。
如果这里的取值为intType,那么android:valueFrom、android:valueTo的值也就要对应的是int类型的数值。
非常注意的是,如果android:valueFrom、android:valueTo的值设置为color类型的值,那么不需要设置这个参数;

4.1.8.2 代码实现

1.在res/animator目录下创建animator_value.xml

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="0"
    android:valueTo="300"
    android:valueType="intType"
    android:duration="1000"
    android:interpolator="@android:anim/bounce_interpolator"
    />

2.加载到程序中

ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animtor_value);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
            int offset = (int) animation.getAnimatedValue();
            tvAnimPropertyValue.layout(offset,offset,offset+tvAnimPropertyValue.getWidth(),offset+tvAnimPropertyValue.getHeight());
      }
});
animator.start();

更多案例

自定义弹性圆控件(配合使用ValueAnimator的ofObject)

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