Animation动画详解(七)——ObjectAnimator基本使用

一、概述

1、引入

上几篇给大家讲了ValueAnimator,但ValueAnimator有个缺点,就是只能对数值对动画计算。我们要想对哪个控件操作,需要监听动画过程,在监听中对控件操作。这样使用起来相比补间动画而言就相对比较麻烦。 
为了能让动画直接与对应控件相关联,以使我们从监听动画过程中解放出来,谷歌的开发人员在ValueAnimator的基础上,又派生了一个类ObjectAnimator; 
由于ObjectAnimator是派生自ValueAnimator的,所以ValueAnimator中所能使用的方法,在ObjectAnimator中都可以正常使用。 
但ObjectAnimator也重写了几个方法,比如ofInt(),ofFloat()等。我们先看看利用ObjectAnimator重写的ofFloat方法如何实现一个动画:(改变透明度)

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"alpha",1,0,1);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下:

我们这里还是直接使用上一篇的框架代码;(当点击start anim时执行动画)从上面的代码中可以看到构造ObjectAnimator的方法非常简单:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)   
  • 第一个参数用于指定这个动画要操作的是哪个控件
  • 第二个参数用于指定这个动画要操作这个控件的哪个属性
  • 第三个参数是可变长参数,这个就跟ValueAnimator中的可变长参数的意义一样了,就是指这个属性值是从哪变到哪。像我们上面的代码中指定的就是将textview的alpha属性从0变到1再变到0;
下面我们再来看一下如何实现旋转效果:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下:

从代码中可以看到,我们只需要改变ofFloat()的第二个参数的值就可以实现对应的动画; 
那么问题来了,我们怎么知道第二个参数的值是啥呢?

2、setter函数

我们再回来看构造改变rotation值的ObjectAnimator的方法

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);  
TextView控件有rotation这个属性吗?没有,不光TextView没有,连它的父类View中也没有这个属性。那它是怎么来改变这个值的呢?其实,ObjectAnimator做动画,并不是根据控件xml中的属性来改变的,而是通过指定属性所对应的set方法来改变的。比如,我们上面指定的改变rotation的属性值,ObjectAnimator在做动画时就会到指定控件(TextView)中去找对应的setRotation()方法来改变控件中对应的值。同样的道理,当我们在最开始的示例代码中,指定改变”alpha”属性值的时候,ObjectAnimator也会到TextView中去找对应的setAlpha()方法。那TextView中都有这些方法吗,有的,这些方法都是从View中继承过来的,在View中有关动画,总共有下面几组set方法:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. //1、透明度:alpha  
  2. public void setAlpha(float alpha)  
  3.   
  4. //2、旋转度数:rotation、rotationX、rotationY  
  5. public void setRotation(float rotation)  
  6. public void setRotationX(float rotationX)  
  7. public void setRotationY(float rotationY)  
  8.   
  9. //3、平移:translationX、translationY  
  10. public void setTranslationX(float translationX)   
  11. public void setTranslationY(float translationY)  
  12.   
  13. //缩放:scaleX、scaleY  
  14. public void setScaleX(float scaleX)  
  15. public void setScaleY(float scaleY)  
可以看到在View中已经实现了有关alpha,rotaion,translate,scale相关的set方法。所以我们在构造ObjectAnimator时可以直接使用。 
在开始逐个看这些函数的使用方法前,我们先做一个总结: 
1、要使用ObjectAnimator来构造对画,要操作的控件中,必须存在对应的属性的set方法 
2、setter 方法的命名必须以骆驼拼写法命名,即set后每个单词首字母大写,其余字母小写,即类似于setPropertyName所对应的属性为propertyName 

下面我们就来看一下上面中各个方法的使用方法及作用。 
有关alpha的用法,上面已经讲过了,下面我们来看看其它的 

(1)、setRotationX、setRotationY与setRotation

  • setRotationX(float rotationX):表示围绕X轴旋转,rotationX表示旋转度数 
  • setRotationY(rotationY):表示围绕Y轴旋转,rotationY表示旋转度数 
  • setRotation(float rotation):表示围绕Z旋转,rotation表示旋转度数 
先来看看setRotationX的效果:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

效果图如下: 


从效果图中明显看出,textview的旋转方法是围绕X轴旋转的,我们设定为从0度旋转到270度再返回0度。 
然后再来看看setRotationY的使用方法与效果:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationY",0,180,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

效果图如下: 


从效果图中明显可以看出围绕Y轴旋转的。 
我们再来看看setRotation的用法与效果:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,270,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

我们上面说了,setRotation是围绕Z轴旋转的,可能有些同学不理解什么是Z轴,我们来看一张图: 


从这张图中,绿色框部分表示手机屏幕,很明显可以看出Z轴就是从屏幕左上角原点向外伸出的一条轴。这样,我们也就可以理解围绕Z轴旋转,为什么是这样子转了。 

(2)、setTranslationX与setTranslationY

  • setTranslationX(float translationX) :表示在X轴上的平移距离,以当前控件为原点,向右为正方向,参数translationX表示移动的距离。 
  • setTranslationY(float translationY) :表示在Y轴上的平移距离,以当前控件为原点,向下为正方向,参数translationY表示移动的距离。 
我们先看看setTranslationX的用法:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationX"0200, -200,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下: 

所以,我们上面在构造动画时,指定的移动距离是(0, 200, -200,0),所以控件会从自身所有位置向右移动200像素,然后再移动到距离原点-200的位置,最后回到原点; 
然后我们来看看setTranslateY的用法:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationY"0200, -100,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下:(为了方便看到效果,将textview垂直居中) 

同样,移动位置的坐标也都是以当前控件所在位置为中心点的。所以对应的移动位置从原点移动向下移动200像素,然后再移动到向下到距原点200像素的位置,最后再回到(0,0)从效果图中很明显可以看出来。 
从上面可以看出:每次移动距离的计算都是以原点为中心的;比如初始动画为ObjectAnimator.ofFloat(tv, “translationY”, 0, 200, -100,0)表示首先从0移动到正方向200的位置,然后再移动到负方向100的位置,最后移动到原点。 

(3)、setScaleX与setScaleY

  • setScaleX(float scaleX):在X轴上缩放,scaleX表示缩放倍数 
  • setScaleY(float scaleY):在Y轴上缩放,scaleY表示缩放倍数 
我们来看看setScaleX的用法:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleX"031);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下: 

在效果图中,从0倍放大到3倍,然后再还原到1倍的原始状态。 
然后再来看看setScaleY的用法

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY"031);  
  2. animator.setDuration(2000);  
  3. animator.start();  
为了更好的看到效果,我把textview垂直居中了,效果图如下: 

源码在文章底部给出 
好了,到这里有关View中自带的set函数讲完了,我们来看看ObjectAnimator是如何实现控件动画效果的。

3、ObjectAnimator动画原理

我们先来看张图: 


在这张图中,将ValueAnimator的动画流程与ObjectAnimator的动画流程做了个对比。 
可以看到ObjectAnimator的动画流程中,也是首先通过加速器产生当前进度的百分比,然后再经过Evaluator生成对应百分比所对应的数字值。这两步与ValueAnimator是完全一样的,唯一不同的是最后一步,在ValueAnimator中,我们要通过添加监听器来监听当前数字值。而在ObjectAnimator中,则是先根据属性值拼装成对应的set函数的名字,比如这里的scaleY的拼装方法就是将属性的第一个字母强制大写后,与set拼接,所以就是setScaleY。然后通过反射找到对应控件的setScaleY(float scaleY)函数,将当前数字值做为setScaleY(float scale)的参数将其传入。 
这里在找到控件的set函数以后,是通过反射来调用这个函数的,有关反射的使用大家可以参考《夯实JAVA基本之二 —— 反射(1):基本类周边信息获取》 
这就是ObjectAnimator的流程,最后一步总结起来就是调用对应属性的set方法,将动画当前数字值做为参数传进去。 
根据上面的流程,这里有几个注意事项: 
(1)、拼接set函数的方法:上面我们也说了是首先是强制将属性的第一个字母大写,然后与set拼接,就是对应的set函数的名字。注意,只是强制将属性的第一个字母大写,后面的部分是保持不变的。反过来,如果我们的函数名命名为setScalePointX(float ),那我们在写属性时可以写成”scalePointX”或者写成“ScalePointX”都是可以的,即第一个字母大小写可以随意,但后面的部分必须与set方法后的大小写保持一致。 
(2)、如何确定函数的参数类型:上面我们知道了如何找到对应的函数名,那对应的参数方法的参数类型如何确定呢?我们在讲ValueAnimator的时候说过,动画过程中产生的数字值与构造时传入的值类型是一样的。由于ObjectAnimator与ValueAnimator在插值器和Evaluator这两步是完全一样的,而当前动画数值的产生是在Evaluator这一步产生的,所以ObjectAnimator的动画中产生的数值类型也是与构造时的类型一样的。那么问题来了,像我们的构造方法。

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY"031);  
由于构造时使用的是ofFloat函数,所以中间值的类型应该是Float类型的,所以在最后一步拼装出来的set函数应该是setScaleY(float xxx)的样式;这时,系统就会利用反射来找到setScaleY(float xxx)函数,并把当前的动画数值做为参数传进去。 
那问题来了,如果没有类似setScaleY(float xxx)的函数,我们只实现了一个setScaleY(int xxx)的函数怎么办?这里虽然函数名一样,但参数类型是不一样的,那么系统就会报一个错误: 

意思就是对应函数的指定参数类型没有找到。 
(3)、调用set函数以后怎么办?从ObjectAnimator的流程可以看到,ObjectAnimator只负责把动画过程中的数值传到对应属性的set函数中就结束了,注意传给set函数以后就结束了!set函数就相当我们在ValueAnimator中添加的监听的作用,set函数中的对控件的操作还是需要我们自己来写的。

那我们来看看View中的setScaleY是怎么实现的吧:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 
  3.  * the view's unscaled width. A value of 1 means that no scaling is applied. 
  4.  * 
  5.  * @param scaleY The scaling factor. 
  6.  * @see #getPivotX() 
  7.  * @see #getPivotY() 
  8.  * 
  9.  * @attr ref android.R.styleable#View_scaleY 
  10.  */  
  11. public void setScaleY(float scaleY) {  
  12.     ensureTransformationInfo();  
  13.     final TransformationInfo info = mTransformationInfo;  
  14.     if (info.mScaleY != scaleY) {  
  15.         invalidateParentCaches();  
  16.         // Double-invalidation is necessary to capture view's old and new areas  
  17.         invalidate(false);  
  18.         info.mScaleY = scaleY;  
  19.         info.mMatrixDirty = true;  
  20.         mPrivateFlags |= DRAWN; // force another invalidation with the new orientation  
  21.         invalidate(false);  
  22.     }  
  23. }  
大家不必理解这一坨代码的意义,因为这些代码是需要读懂View的整体流程以后才能看得懂的,只需要跟着我的步骤来理解就行。这段代码总共分为两部分:第一步重新设置当前控件的参数,第二步调用Invalidate()强制重绘; 
所以在重绘时,控件就会根据最新的控件参数来绘制了,所以我们就看到当前控件被缩放了。 
(4)、set函数调用频率是多少: 由于我们知道动画在进行时,每隔十几毫秒会刷新一次,所以我们的set函数也会每隔十几毫秒会被调用一次。 
讲了这么多,就是为了强调一点:ObjectAnimator只负责把当前运动动画的数值传给set函数。至于set函数里面怎么来做,是我们自己的事了。 
好了,在知道了ObjectAnimator的原理以后,下面就来看看如何自定义一个ObjectAnimator的属性吧。

二、自定义ObjectAnimator属性

上面我们已经看了使用View自带的set函数所对应属性的方法,而且理解了ObjectAnimator的动画实现原理,下面我们来自定义一个属性来看看实现效果吧。 
我们在开始之前再来捋一下ObjectAnimator的动画设置流程:ObjectAnimator需要指定操作的控件对象,在开始动画时,到控件类中去寻找设置属性所对应的set函数,然后把动画中间值做为参数传给这个set函数并执行它。 
所以,我们说了,控件类中必须所要设置属性所要对应的set函数。所以为了自由控制控件的实现,我们这里自定义一个控件。大家知道在这个自定义控件中,肯定存在一个set函数与我们自定义的属性相对应。 
我们先来看看这段要实现的效果:

这个效果图与我们上篇自定义控件实现的效果差不多,这个控件中存在一个圆形,也是在动画时先将这个圆形放大,然后再将圆形还原。

1、保存圆形信息类——Point

为了,保存圆形的信息,我们先定义一个类:(Point.java)

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class Point {  
  2.     private int mRadius;  
  3.   
  4.     public Point(int radius){  
  5.         mRadius = radius;  
  6.     }  
  7.   
  8.     public int getRadius() {  
  9.         return mRadius;  
  10.     }  
  11.   
  12.     public void setRadius(int radius) {  
  13.         mRadius = radius;  
  14.     }  
  15. }  
这个类很好理解,只有一个成员变量mRadius,表示圆的半径。

2、自定义控件——MyPointView

然后我们自定义一个控件MyPointView,完整代码如下:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class MyPointView extends View {  
  2.     private Point mPoint = new Point(100);  
  3.   
  4.     public MyPointView(Context context, AttributeSet attrs) {  
  5.         super(context, attrs);  
  6.     }  
  7.   
  8.     @Override  
  9.     protected void onDraw(Canvas canvas) {  
  10.         if (mPoint != null){  
  11.             Paint paint = new Paint();  
  12.             paint.setAntiAlias(true);  
  13.             paint.setColor(Color.RED);  
  14.             paint.setStyle(Paint.Style.FILL);  
  15.             canvas.drawCircle(300,300,mPoint.getRadius(),paint);  
  16.         }  
  17.         super.onDraw(canvas);  
  18.     }  
  19.   
  20.     void setPointRadius(int radius){  
  21.         mPoint.setRadius(radius);  
  22.         invalidate();  
  23.     }  
  24.   
  25. }  
在这段代码中,首先来看我们前面讲到的set函数:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. void setPointRadius(int radius){  
  2.     mPoint.setRadius(radius);  
  3.     invalidate();  
  4. }  
第一点,这个set函数所对应的属性应该是pointRadius或者PointRadius。前面我们已经讲了第一个字母大小写无所谓,后面的字母必须保持与set函数完全一致。 
第二点,在setPointRadius中,先将当前动画传过来的值保存到mPoint中,做为当前圆形的半径。然后强制界面刷新 

在界面刷新后,就开始执行onDraw()函数:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     if (mPoint != null){  
  4.         Paint paint = new Paint();  
  5.         paint.setAntiAlias(true);  
  6.         paint.setColor(Color.RED);  
  7.         paint.setStyle(Paint.Style.FILL);  
  8.         canvas.drawCircle(300,300,mPoint.getRadius(),paint);  
  9.     }  
  10.     super.onDraw(canvas);  
  11. }  
在onDraw函数中,就是根据当前mPoint的半径值在(300,300)点外画一个圆;有关画圆的知识,大家可以参考 《android Graphics(一):概述及基本几何图形绘制》

3、使用MyPointView

首先,在MyActivity的布局中添加MyPointView的使用(main.xml):
[html]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.                 android:orientation="vertical"  
  4.                 android:layout_width="fill_parent"  
  5.                 android:layout_height="fill_parent">  
  6.   
  7.     <Button  
  8.             android:id="@+id/btn"  
  9.             android:layout_width="wrap_content"  
  10.             android:layout_height="wrap_content"  
  11.             android:layout_alignParentLeft="true"  
  12.             android:padding="10dp"  
  13.             android:text="start anim"  
  14.             />  
  15.   
  16.     <Button  
  17.             android:id="@+id/btn_cancel"  
  18.             android:layout_width="wrap_content"  
  19.             android:layout_height="wrap_content"  
  20.             android:layout_alignParentRight="true"  
  21.             android:padding="10dp"  
  22.             android:text="cancel anim"  
  23.             />  
  24.     <TextView  
  25.             android:id="@+id/tv"  
  26.             android:layout_width="100dp"  
  27.             android:layout_height="wrap_content"  
  28.             android:layout_centerHorizontal="true"  
  29.             android:gravity="center"  
  30.             android:padding="10dp"  
  31.             android:background="#ffff00"  
  32.             android:text="Hello qijian"/>  
  33.   
  34.     <com.example.BlogObjectAnimator1.MyPointView  
  35.             android:id="@+id/pointview"  
  36.             android:layout_width="match_parent"  
  37.             android:layout_height="match_parent"  
  38.             android:layout_below="@id/tv"/>  
  39.   
  40. </RelativeLayout>  
布局代码很好理解,根据效果图中的布局效果来理解,非常容易,就不再多讲 
然后看看在MyActivity中,点击start anim后的处理方法:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class MyActivity extends Activity {  
  2.     private Button btnStart;  
  3.     private MyPointView mPointView;  
  4.   
  5.     @Override  
  6.     public void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.   
  10.         btnStart = (Button) findViewById(R.id.btn);  
  11.         mPointView = (MyPointView)findViewById(R.id.pointview);  
  12.   
  13.         btnStart.setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View v) {  
  16.                 doPointViewAnimation();  
  17.             }  
  18.         });  
  19.     }  
  20.   …………  
  21. }       
在点击start anim按钮后,开始执行doPointViewAnimation()函数,doPointViewAnimation()函数代码如下:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. private void doPointViewAnimation(){  
  2.      ObjectAnimator animator = ObjectAnimator.ofInt(mPointView, "pointRadius"0300100);  
  3.       animator.setDuration(2000);  
  4.       animator.start();  
  5. }  
在这段代码中,着重看ObjectAnimator的构造方法,首先要操作的控件对象是mPointView,然后对应的属性是pointRadius,然后值是从0到300再到100; 
所以在动画开始以后,ObjectAnimator就会实时地把动画中产生的值做为参数传给MyPointView类中的setPointRadius(int radius)函数,然后调用setPointRadius(int radius)。由于我们在setPointRadius(int radius)中实时地设置圆形的半径值然后强制重绘当前界面,所以可以看到圆形的半径会随着动画的进行而改变。 
源码在文章底部给出

三、常用函数

有关常用函数这一节其实没有太多讲的必要。因为ObjectAnimator的函数都是从ValueAnimator中继承而来的,所以用法和效果与ValueAnimator是完全一样的。我们这里只讲解一下Evaluator的用法,其它的也就不再讲了。

1、使用ArgbEvaluator

我们搜一下TextView所有的函数发现,TextView有一个set函数能够改变背景色:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public void setBackgroundColor(int color);  
大家可以回想到,我们在ValueAnimator中也曾改变过背景色,使用的是ArgbEvaluator。在这里我们再回顾下ArgbEvaluator,它的实现代码如下:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class ArgbEvaluator implements TypeEvaluator {  
  2.     public Object evaluate(float fraction, Object startValue, Object endValue) {  
  3.         int startInt = (Integer) startValue;  
  4.         int startA = (startInt >> 24);  
  5.         int startR = (startInt >> 16) & 0xff;  
  6.         int startG = (startInt >> 8) & 0xff;  
  7.         int startB = startInt & 0xff;  
  8.   
  9.         int endInt = (Integer) endValue;  
  10.         int endA = (endInt >> 24);  
  11.         int endR = (endInt >> 16) & 0xff;  
  12.         int endG = (endInt >> 8) & 0xff;  
  13.         int endB = endInt & 0xff;  
  14.   
  15.         return (int)((startA + (int)(fraction * (endA - startA))) << 24) |  
  16.                 (int)((startR + (int)(fraction * (endR - startR))) << 16) |  
  17.                 (int)((startG + (int)(fraction * (endG - startG))) << 8) |  
  18.                 (int)((startB + (int)(fraction * (endB - startB))));  
  19.     }  
  20. }  
有关它具体实现的原理,前面篇章中我们已经讲过了,这里主要说一点,ArgbEvaluator的返回值是Integer类型,所以我们要使用ArgbEvaluator的话,构造ObjectAnimator时必须使用ofInt() 
下面我们来看看使用ArgbEvaluator的代码:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofInt(tv, "BackgroundColor"0xffff00ff0xffffff000xffff00ff);  
  2. animator.setDuration(8000);  
  3. animator.setEvaluator(new ArgbEvaluator());  
  4. animator.start();  
然后我们来看下代码效果: 

源码在文章底部给出

2、其它函数

下面把其它所涉及到的函数的列表列在下面,大家可以参考ValueAnimator的使用方法来使用。有关自定义插值器和Evaluator的部分,可以参考 《Animation动画详解(五)——高级进阶(一)》 

(1)、常用函数

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 设置动画时长,单位是毫秒 
  3.  */  
  4. ValueAnimator setDuration(long duration)  
  5. /** 
  6.  * 获取ValueAnimator在运动时,当前运动点的值 
  7.  */  
  8. Object getAnimatedValue();  
  9. /** 
  10.  * 开始动画 
  11.  */  
  12. void start()  
  13. /** 
  14.  * 设置循环次数,设置为INFINITE表示无限循环 
  15.  */  
  16. void setRepeatCount(int value)  
  17. /** 
  18.  * 设置循环模式 
  19.  * value取值有RESTART,REVERSE, 
  20.  */  
  21. void setRepeatMode(int value)  
  22. /** 
  23.  * 取消动画 
  24.  */  
  25. void cancel()  

(2)、监听器相关

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 监听器一:监听动画变化时的实时值 
  3.  */  
  4. public static interface AnimatorUpdateListener {  
  5.     void onAnimationUpdate(ValueAnimator animation);  
  6. }  
  7. //添加方法为:public void addUpdateListener(AnimatorUpdateListener listener)  
  8. /** 
  9.  * 监听器二:监听动画变化时四个状态 
  10.  */  
  11. public static interface AnimatorListener {  
  12.     void onAnimationStart(Animator animation);  
  13.     void onAnimationEnd(Animator animation);  
  14.     void onAnimationCancel(Animator animation);  
  15.     void onAnimationRepeat(Animator animation);  
  16. }  
  17. //添加方法为:public void addListener(AnimatorListener listener)   

(3)、插值器与Evaluator

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 设置插值器 
  3.  */  
  4. public void setInterpolator(TimeInterpolator value)  
  5. /** 
  6.  * 设置Evaluator 
  7.  */  
  8. public void setEvaluator(TypeEvaluator value)  
到这里,有关ObjectAnimator的知识就讲完了,下篇再讲讲联合动画和xml中实现动画的方法。

如果本文有帮到你,记得加关注哦

源码下载地址:

csdn:

github:https://github.com/harvic/BlogResForGitHub


转自:http://blog.csdn.net/xuepeng0728119/article/details/50607534

0

一、概述

1、引入

上几篇给大家讲了ValueAnimator,但ValueAnimator有个缺点,就是只能对数值对动画计算。我们要想对哪个控件操作,需要监听动画过程,在监听中对控件操作。这样使用起来相比补间动画而言就相对比较麻烦。 
为了能让动画直接与对应控件相关联,以使我们从监听动画过程中解放出来,谷歌的开发人员在ValueAnimator的基础上,又派生了一个类ObjectAnimator; 
由于ObjectAnimator是派生自ValueAnimator的,所以ValueAnimator中所能使用的方法,在ObjectAnimator中都可以正常使用。 
但ObjectAnimator也重写了几个方法,比如ofInt(),ofFloat()等。我们先看看利用ObjectAnimator重写的ofFloat方法如何实现一个动画:(改变透明度)

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"alpha",1,0,1);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下:

我们这里还是直接使用上一篇的框架代码;(当点击start anim时执行动画)从上面的代码中可以看到构造ObjectAnimator的方法非常简单:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)   
  • 第一个参数用于指定这个动画要操作的是哪个控件
  • 第二个参数用于指定这个动画要操作这个控件的哪个属性
  • 第三个参数是可变长参数,这个就跟ValueAnimator中的可变长参数的意义一样了,就是指这个属性值是从哪变到哪。像我们上面的代码中指定的就是将textview的alpha属性从0变到1再变到0;
下面我们再来看一下如何实现旋转效果:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下:

从代码中可以看到,我们只需要改变ofFloat()的第二个参数的值就可以实现对应的动画; 
那么问题来了,我们怎么知道第二个参数的值是啥呢?

2、setter函数

我们再回来看构造改变rotation值的ObjectAnimator的方法

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);  
TextView控件有rotation这个属性吗?没有,不光TextView没有,连它的父类View中也没有这个属性。那它是怎么来改变这个值的呢?其实,ObjectAnimator做动画,并不是根据控件xml中的属性来改变的,而是通过指定属性所对应的set方法来改变的。比如,我们上面指定的改变rotation的属性值,ObjectAnimator在做动画时就会到指定控件(TextView)中去找对应的setRotation()方法来改变控件中对应的值。同样的道理,当我们在最开始的示例代码中,指定改变”alpha”属性值的时候,ObjectAnimator也会到TextView中去找对应的setAlpha()方法。那TextView中都有这些方法吗,有的,这些方法都是从View中继承过来的,在View中有关动画,总共有下面几组set方法:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. //1、透明度:alpha  
  2. public void setAlpha(float alpha)  
  3.   
  4. //2、旋转度数:rotation、rotationX、rotationY  
  5. public void setRotation(float rotation)  
  6. public void setRotationX(float rotationX)  
  7. public void setRotationY(float rotationY)  
  8.   
  9. //3、平移:translationX、translationY  
  10. public void setTranslationX(float translationX)   
  11. public void setTranslationY(float translationY)  
  12.   
  13. //缩放:scaleX、scaleY  
  14. public void setScaleX(float scaleX)  
  15. public void setScaleY(float scaleY)  
可以看到在View中已经实现了有关alpha,rotaion,translate,scale相关的set方法。所以我们在构造ObjectAnimator时可以直接使用。 
在开始逐个看这些函数的使用方法前,我们先做一个总结: 
1、要使用ObjectAnimator来构造对画,要操作的控件中,必须存在对应的属性的set方法 
2、setter 方法的命名必须以骆驼拼写法命名,即set后每个单词首字母大写,其余字母小写,即类似于setPropertyName所对应的属性为propertyName 

下面我们就来看一下上面中各个方法的使用方法及作用。 
有关alpha的用法,上面已经讲过了,下面我们来看看其它的 

(1)、setRotationX、setRotationY与setRotation

  • setRotationX(float rotationX):表示围绕X轴旋转,rotationX表示旋转度数 
  • setRotationY(rotationY):表示围绕Y轴旋转,rotationY表示旋转度数 
  • setRotation(float rotation):表示围绕Z旋转,rotation表示旋转度数 
先来看看setRotationX的效果:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

效果图如下: 


从效果图中明显看出,textview的旋转方法是围绕X轴旋转的,我们设定为从0度旋转到270度再返回0度。 
然后再来看看setRotationY的使用方法与效果:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationY",0,180,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

效果图如下: 


从效果图中明显可以看出围绕Y轴旋转的。 
我们再来看看setRotation的用法与效果:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,270,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  

我们上面说了,setRotation是围绕Z轴旋转的,可能有些同学不理解什么是Z轴,我们来看一张图: 


从这张图中,绿色框部分表示手机屏幕,很明显可以看出Z轴就是从屏幕左上角原点向外伸出的一条轴。这样,我们也就可以理解围绕Z轴旋转,为什么是这样子转了。 

(2)、setTranslationX与setTranslationY

  • setTranslationX(float translationX) :表示在X轴上的平移距离,以当前控件为原点,向右为正方向,参数translationX表示移动的距离。 
  • setTranslationY(float translationY) :表示在Y轴上的平移距离,以当前控件为原点,向下为正方向,参数translationY表示移动的距离。 
我们先看看setTranslationX的用法:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationX"0200, -200,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下: 

所以,我们上面在构造动画时,指定的移动距离是(0, 200, -200,0),所以控件会从自身所有位置向右移动200像素,然后再移动到距离原点-200的位置,最后回到原点; 
然后我们来看看setTranslateY的用法:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationY"0200, -100,0);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下:(为了方便看到效果,将textview垂直居中) 

同样,移动位置的坐标也都是以当前控件所在位置为中心点的。所以对应的移动位置从原点移动向下移动200像素,然后再移动到向下到距原点200像素的位置,最后再回到(0,0)从效果图中很明显可以看出来。 
从上面可以看出:每次移动距离的计算都是以原点为中心的;比如初始动画为ObjectAnimator.ofFloat(tv, “translationY”, 0, 200, -100,0)表示首先从0移动到正方向200的位置,然后再移动到负方向100的位置,最后移动到原点。 

(3)、setScaleX与setScaleY

  • setScaleX(float scaleX):在X轴上缩放,scaleX表示缩放倍数 
  • setScaleY(float scaleY):在Y轴上缩放,scaleY表示缩放倍数 
我们来看看setScaleX的用法:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleX"031);  
  2. animator.setDuration(2000);  
  3. animator.start();  
效果图如下: 

在效果图中,从0倍放大到3倍,然后再还原到1倍的原始状态。 
然后再来看看setScaleY的用法

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY"031);  
  2. animator.setDuration(2000);  
  3. animator.start();  
为了更好的看到效果,我把textview垂直居中了,效果图如下: 

源码在文章底部给出 
好了,到这里有关View中自带的set函数讲完了,我们来看看ObjectAnimator是如何实现控件动画效果的。

3、ObjectAnimator动画原理

我们先来看张图: 


在这张图中,将ValueAnimator的动画流程与ObjectAnimator的动画流程做了个对比。 
可以看到ObjectAnimator的动画流程中,也是首先通过加速器产生当前进度的百分比,然后再经过Evaluator生成对应百分比所对应的数字值。这两步与ValueAnimator是完全一样的,唯一不同的是最后一步,在ValueAnimator中,我们要通过添加监听器来监听当前数字值。而在ObjectAnimator中,则是先根据属性值拼装成对应的set函数的名字,比如这里的scaleY的拼装方法就是将属性的第一个字母强制大写后,与set拼接,所以就是setScaleY。然后通过反射找到对应控件的setScaleY(float scaleY)函数,将当前数字值做为setScaleY(float scale)的参数将其传入。 
这里在找到控件的set函数以后,是通过反射来调用这个函数的,有关反射的使用大家可以参考《夯实JAVA基本之二 —— 反射(1):基本类周边信息获取》 
这就是ObjectAnimator的流程,最后一步总结起来就是调用对应属性的set方法,将动画当前数字值做为参数传进去。 
根据上面的流程,这里有几个注意事项: 
(1)、拼接set函数的方法:上面我们也说了是首先是强制将属性的第一个字母大写,然后与set拼接,就是对应的set函数的名字。注意,只是强制将属性的第一个字母大写,后面的部分是保持不变的。反过来,如果我们的函数名命名为setScalePointX(float ),那我们在写属性时可以写成”scalePointX”或者写成“ScalePointX”都是可以的,即第一个字母大小写可以随意,但后面的部分必须与set方法后的大小写保持一致。 
(2)、如何确定函数的参数类型:上面我们知道了如何找到对应的函数名,那对应的参数方法的参数类型如何确定呢?我们在讲ValueAnimator的时候说过,动画过程中产生的数字值与构造时传入的值类型是一样的。由于ObjectAnimator与ValueAnimator在插值器和Evaluator这两步是完全一样的,而当前动画数值的产生是在Evaluator这一步产生的,所以ObjectAnimator的动画中产生的数值类型也是与构造时的类型一样的。那么问题来了,像我们的构造方法。

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY"031);  
由于构造时使用的是ofFloat函数,所以中间值的类型应该是Float类型的,所以在最后一步拼装出来的set函数应该是setScaleY(float xxx)的样式;这时,系统就会利用反射来找到setScaleY(float xxx)函数,并把当前的动画数值做为参数传进去。 
那问题来了,如果没有类似setScaleY(float xxx)的函数,我们只实现了一个setScaleY(int xxx)的函数怎么办?这里虽然函数名一样,但参数类型是不一样的,那么系统就会报一个错误: 

意思就是对应函数的指定参数类型没有找到。 
(3)、调用set函数以后怎么办?从ObjectAnimator的流程可以看到,ObjectAnimator只负责把动画过程中的数值传到对应属性的set函数中就结束了,注意传给set函数以后就结束了!set函数就相当我们在ValueAnimator中添加的监听的作用,set函数中的对控件的操作还是需要我们自己来写的。

那我们来看看View中的setScaleY是怎么实现的吧:

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 
  3.  * the view's unscaled width. A value of 1 means that no scaling is applied. 
  4.  * 
  5.  * @param scaleY The scaling factor. 
  6.  * @see #getPivotX() 
  7.  * @see #getPivotY() 
  8.  * 
  9.  * @attr ref android.R.styleable#View_scaleY 
  10.  */  
  11. public void setScaleY(float scaleY) {  
  12.     ensureTransformationInfo();  
  13.     final TransformationInfo info = mTransformationInfo;  
  14.     if (info.mScaleY != scaleY) {  
  15.         invalidateParentCaches();  
  16.         // Double-invalidation is necessary to capture view's old and new areas  
  17.         invalidate(false);  
  18.         info.mScaleY = scaleY;  
  19.         info.mMatrixDirty = true;  
  20.         mPrivateFlags |= DRAWN; // force another invalidation with the new orientation  
  21.         invalidate(false);  
  22.     }  
  23. }  
大家不必理解这一坨代码的意义,因为这些代码是需要读懂View的整体流程以后才能看得懂的,只需要跟着我的步骤来理解就行。这段代码总共分为两部分:第一步重新设置当前控件的参数,第二步调用Invalidate()强制重绘; 
所以在重绘时,控件就会根据最新的控件参数来绘制了,所以我们就看到当前控件被缩放了。 
(4)、set函数调用频率是多少: 由于我们知道动画在进行时,每隔十几毫秒会刷新一次,所以我们的set函数也会每隔十几毫秒会被调用一次。 
讲了这么多,就是为了强调一点:ObjectAnimator只负责把当前运动动画的数值传给set函数。至于set函数里面怎么来做,是我们自己的事了。 
好了,在知道了ObjectAnimator的原理以后,下面就来看看如何自定义一个ObjectAnimator的属性吧。

二、自定义ObjectAnimator属性

上面我们已经看了使用View自带的set函数所对应属性的方法,而且理解了ObjectAnimator的动画实现原理,下面我们来自定义一个属性来看看实现效果吧。 
我们在开始之前再来捋一下ObjectAnimator的动画设置流程:ObjectAnimator需要指定操作的控件对象,在开始动画时,到控件类中去寻找设置属性所对应的set函数,然后把动画中间值做为参数传给这个set函数并执行它。 
所以,我们说了,控件类中必须所要设置属性所要对应的set函数。所以为了自由控制控件的实现,我们这里自定义一个控件。大家知道在这个自定义控件中,肯定存在一个set函数与我们自定义的属性相对应。 
我们先来看看这段要实现的效果:

这个效果图与我们上篇自定义控件实现的效果差不多,这个控件中存在一个圆形,也是在动画时先将这个圆形放大,然后再将圆形还原。

1、保存圆形信息类——Point

为了,保存圆形的信息,我们先定义一个类:(Point.java)

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class Point {  
  2.     private int mRadius;  
  3.   
  4.     public Point(int radius){  
  5.         mRadius = radius;  
  6.     }  
  7.   
  8.     public int getRadius() {  
  9.         return mRadius;  
  10.     }  
  11.   
  12.     public void setRadius(int radius) {  
  13.         mRadius = radius;  
  14.     }  
  15. }  
这个类很好理解,只有一个成员变量mRadius,表示圆的半径。

2、自定义控件——MyPointView

然后我们自定义一个控件MyPointView,完整代码如下:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class MyPointView extends View {  
  2.     private Point mPoint = new Point(100);  
  3.   
  4.     public MyPointView(Context context, AttributeSet attrs) {  
  5.         super(context, attrs);  
  6.     }  
  7.   
  8.     @Override  
  9.     protected void onDraw(Canvas canvas) {  
  10.         if (mPoint != null){  
  11.             Paint paint = new Paint();  
  12.             paint.setAntiAlias(true);  
  13.             paint.setColor(Color.RED);  
  14.             paint.setStyle(Paint.Style.FILL);  
  15.             canvas.drawCircle(300,300,mPoint.getRadius(),paint);  
  16.         }  
  17.         super.onDraw(canvas);  
  18.     }  
  19.   
  20.     void setPointRadius(int radius){  
  21.         mPoint.setRadius(radius);  
  22.         invalidate();  
  23.     }  
  24.   
  25. }  
在这段代码中,首先来看我们前面讲到的set函数:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. void setPointRadius(int radius){  
  2.     mPoint.setRadius(radius);  
  3.     invalidate();  
  4. }  
第一点,这个set函数所对应的属性应该是pointRadius或者PointRadius。前面我们已经讲了第一个字母大小写无所谓,后面的字母必须保持与set函数完全一致。 
第二点,在setPointRadius中,先将当前动画传过来的值保存到mPoint中,做为当前圆形的半径。然后强制界面刷新 

在界面刷新后,就开始执行onDraw()函数:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. protected void onDraw(Canvas canvas) {  
  3.     if (mPoint != null){  
  4.         Paint paint = new Paint();  
  5.         paint.setAntiAlias(true);  
  6.         paint.setColor(Color.RED);  
  7.         paint.setStyle(Paint.Style.FILL);  
  8.         canvas.drawCircle(300,300,mPoint.getRadius(),paint);  
  9.     }  
  10.     super.onDraw(canvas);  
  11. }  
在onDraw函数中,就是根据当前mPoint的半径值在(300,300)点外画一个圆;有关画圆的知识,大家可以参考 《android Graphics(一):概述及基本几何图形绘制》

3、使用MyPointView

首先,在MyActivity的布局中添加MyPointView的使用(main.xml):
[html]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.                 android:orientation="vertical"  
  4.                 android:layout_width="fill_parent"  
  5.                 android:layout_height="fill_parent">  
  6.   
  7.     <Button  
  8.             android:id="@+id/btn"  
  9.             android:layout_width="wrap_content"  
  10.             android:layout_height="wrap_content"  
  11.             android:layout_alignParentLeft="true"  
  12.             android:padding="10dp"  
  13.             android:text="start anim"  
  14.             />  
  15.   
  16.     <Button  
  17.             android:id="@+id/btn_cancel"  
  18.             android:layout_width="wrap_content"  
  19.             android:layout_height="wrap_content"  
  20.             android:layout_alignParentRight="true"  
  21.             android:padding="10dp"  
  22.             android:text="cancel anim"  
  23.             />  
  24.     <TextView  
  25.             android:id="@+id/tv"  
  26.             android:layout_width="100dp"  
  27.             android:layout_height="wrap_content"  
  28.             android:layout_centerHorizontal="true"  
  29.             android:gravity="center"  
  30.             android:padding="10dp"  
  31.             android:background="#ffff00"  
  32.             android:text="Hello qijian"/>  
  33.   
  34.     <com.example.BlogObjectAnimator1.MyPointView  
  35.             android:id="@+id/pointview"  
  36.             android:layout_width="match_parent"  
  37.             android:layout_height="match_parent"  
  38.             android:layout_below="@id/tv"/>  
  39.   
  40. </RelativeLayout>  
布局代码很好理解,根据效果图中的布局效果来理解,非常容易,就不再多讲 
然后看看在MyActivity中,点击start anim后的处理方法:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class MyActivity extends Activity {  
  2.     private Button btnStart;  
  3.     private MyPointView mPointView;  
  4.   
  5.     @Override  
  6.     public void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.   
  10.         btnStart = (Button) findViewById(R.id.btn);  
  11.         mPointView = (MyPointView)findViewById(R.id.pointview);  
  12.   
  13.         btnStart.setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View v) {  
  16.                 doPointViewAnimation();  
  17.             }  
  18.         });  
  19.     }  
  20.   …………  
  21. }       
在点击start anim按钮后,开始执行doPointViewAnimation()函数,doPointViewAnimation()函数代码如下:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. private void doPointViewAnimation(){  
  2.      ObjectAnimator animator = ObjectAnimator.ofInt(mPointView, "pointRadius"0300100);  
  3.       animator.setDuration(2000);  
  4.       animator.start();  
  5. }  
在这段代码中,着重看ObjectAnimator的构造方法,首先要操作的控件对象是mPointView,然后对应的属性是pointRadius,然后值是从0到300再到100; 
所以在动画开始以后,ObjectAnimator就会实时地把动画中产生的值做为参数传给MyPointView类中的setPointRadius(int radius)函数,然后调用setPointRadius(int radius)。由于我们在setPointRadius(int radius)中实时地设置圆形的半径值然后强制重绘当前界面,所以可以看到圆形的半径会随着动画的进行而改变。 
源码在文章底部给出

三、常用函数

有关常用函数这一节其实没有太多讲的必要。因为ObjectAnimator的函数都是从ValueAnimator中继承而来的,所以用法和效果与ValueAnimator是完全一样的。我们这里只讲解一下Evaluator的用法,其它的也就不再讲了。

1、使用ArgbEvaluator

我们搜一下TextView所有的函数发现,TextView有一个set函数能够改变背景色:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public void setBackgroundColor(int color);  
大家可以回想到,我们在ValueAnimator中也曾改变过背景色,使用的是ArgbEvaluator。在这里我们再回顾下ArgbEvaluator,它的实现代码如下:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. public class ArgbEvaluator implements TypeEvaluator {  
  2.     public Object evaluate(float fraction, Object startValue, Object endValue) {  
  3.         int startInt = (Integer) startValue;  
  4.         int startA = (startInt >> 24);  
  5.         int startR = (startInt >> 16) & 0xff;  
  6.         int startG = (startInt >> 8) & 0xff;  
  7.         int startB = startInt & 0xff;  
  8.   
  9.         int endInt = (Integer) endValue;  
  10.         int endA = (endInt >> 24);  
  11.         int endR = (endInt >> 16) & 0xff;  
  12.         int endG = (endInt >> 8) & 0xff;  
  13.         int endB = endInt & 0xff;  
  14.   
  15.         return (int)((startA + (int)(fraction * (endA - startA))) << 24) |  
  16.                 (int)((startR + (int)(fraction * (endR - startR))) << 16) |  
  17.                 (int)((startG + (int)(fraction * (endG - startG))) << 8) |  
  18.                 (int)((startB + (int)(fraction * (endB - startB))));  
  19.     }  
  20. }  
有关它具体实现的原理,前面篇章中我们已经讲过了,这里主要说一点,ArgbEvaluator的返回值是Integer类型,所以我们要使用ArgbEvaluator的话,构造ObjectAnimator时必须使用ofInt() 
下面我们来看看使用ArgbEvaluator的代码:
[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. ObjectAnimator animator = ObjectAnimator.ofInt(tv, "BackgroundColor"0xffff00ff0xffffff000xffff00ff);  
  2. animator.setDuration(8000);  
  3. animator.setEvaluator(new ArgbEvaluator());  
  4. animator.start();  
然后我们来看下代码效果: 

源码在文章底部给出

2、其它函数

下面把其它所涉及到的函数的列表列在下面,大家可以参考ValueAnimator的使用方法来使用。有关自定义插值器和Evaluator的部分,可以参考 《Animation动画详解(五)——高级进阶(一)》 

(1)、常用函数

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 设置动画时长,单位是毫秒 
  3.  */  
  4. ValueAnimator setDuration(long duration)  
  5. /** 
  6.  * 获取ValueAnimator在运动时,当前运动点的值 
  7.  */  
  8. Object getAnimatedValue();  
  9. /** 
  10.  * 开始动画 
  11.  */  
  12. void start()  
  13. /** 
  14.  * 设置循环次数,设置为INFINITE表示无限循环 
  15.  */  
  16. void setRepeatCount(int value)  
  17. /** 
  18.  * 设置循环模式 
  19.  * value取值有RESTART,REVERSE, 
  20.  */  
  21. void setRepeatMode(int value)  
  22. /** 
  23.  * 取消动画 
  24.  */  
  25. void cancel()  

(2)、监听器相关

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 监听器一:监听动画变化时的实时值 
  3.  */  
  4. public static interface AnimatorUpdateListener {  
  5.     void onAnimationUpdate(ValueAnimator animation);  
  6. }  
  7. //添加方法为:public void addUpdateListener(AnimatorUpdateListener listener)  
  8. /** 
  9.  * 监听器二:监听动画变化时四个状态 
  10.  */  
  11. public static interface AnimatorListener {  
  12.     void onAnimationStart(Animator animation);  
  13.     void onAnimationEnd(Animator animation);  
  14.     void onAnimationCancel(Animator animation);  
  15.     void onAnimationRepeat(Animator animation);  
  16. }  
  17. //添加方法为:public void addListener(AnimatorListener listener)   

(3)、插值器与Evaluator

[java]  view plain  copy
 
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 设置插值器 
  3.  */  
  4. public void setInterpolator(TimeInterpolator value)  
  5. /** 
  6.  * 设置Evaluator 
  7.  */  
  8. public void setEvaluator(TypeEvaluator value)  
到这里,有关ObjectAnimator的知识就讲完了,下篇再讲讲联合动画和xml中实现动画的方法。

如果本文有帮到你,记得加关注哦

源码下载地址:

csdn:

github:https://github.com/harvic/BlogResForGitHub


转自:http://blog.csdn.net/xuepeng0728119/article/details/50607534

猜你喜欢

转载自blog.csdn.net/huanglei201502/article/details/78043411