动画

Android中动画分为3种:

  1. Tween Animation(View Animation):通过对场景里的对象不断做图像变换(平移、缩放、旋转)产生动画效果,即是一种渐变动画;
  2. Frame Animation(Drawable Animation):顺序播放事先做好的图像,是一种画面转换动画。
  3. Property Animation:属性动画,通过动态地改变对象的属性(一般有setxx,就可以改变xx)从而达到动画效果,属性动画为API 11新特性。与Tween Animation是属性动画实现真正的移动,如点击事件会在他最终的位置。而Tween Animation还有在它最初的位置

一 Tween Animation

 Tween Animation有四种形式:

  l  alpha              渐变透明度动画效果

  l  scale              渐变尺寸伸缩动画效果

  l  translate         画面位置移动动画效果

  l  rotate              画面旋转动画效果

        这四种动画实现方式都是通过Animation类AnimationUtils配合实现。

可以通过xml实现:动画的XML文件在工程中res/anim目录。

例如:rotate.xml,《set》开头表示可以显示动画集合

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <set xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     android:fillAfter = "false"  
  5.     android:zAdjustment="bottom"  
  6.     >  
  7.     <rotate  
  8.         android:fromDegrees="0"  
  9.         android:toDegrees="360"  
  10.         android:pivotX="50%"  
  11.         android:pivotY="50%"  
  12.         android:duration="4000"  
  13.         />  
  14. </set>  

使用动画

[java]  view plain  copy
  1. Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.rotate);  
  2.   
  3. //监听动画的状态(开始,结束)  
  4. anim.setAnimationListener(new EffectAnimationListener());  
  5. textWidget = (TextView)findViewById(R.id.text_widget);  
  6. textWidget.setText("画面旋转动画效果");  
  7. textWidget.startAnimation(anim);  

fillAfter表示是否需要保存动画状态

repeatCount     动画再次重复的次数  
repeatMode      这一次反转上一次的效果   
fillAfter       动画结束后,view停留在动画结束时的位置  view的实际位置并没有改变 

二 Frame Animation

  Frame Animation是顺序播放事先做好的图像,跟电影类似。不同于animation package,Android SDK提供了另外一个类AnimationDrawable来定义使用Frame Animation。

利用xml文件实现:res/drawable-hdpi/frame.xml:《animation-list
[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <animation-list  
  4.   xmlns:android="http://schemas.android.com/apk/res/android"  
  5.   android:oneshot="true"  
  6.   >  
  7.        <item android:drawable="@drawable/p1" android:duration="1000"></item>  
  8.        <item android:drawable="@drawable/p2" android:duration="1000"></item>  
  9.        <item android:drawable="@drawable/p3" android:duration="1000"></item>  
  10.        <item android:drawable="@drawable/p4" android:duration="1000"></item>  
  11.        <item android:drawable="@drawable/p5" android:duration="1000"></item>  
  12.        <item android:drawable="@drawable/p6" android:duration="1000"></item>  
  13. </animation-list>  
使用动画

[java]  view plain  copy
  1. AnimationDrawable anim = (AnimationDrawable)getResources().  
  2. getDrawable(R.drawable.frame);  
  3. textWidget = (TextView)findViewById(R.id.text_widget);  
  4. textWidget.setText("背景渐变动画效果");  
  5. textWidget.setBackgroundDrawable(anim);  
  6. anim.start();  

注意。也可以直接在xml设置背景


这里有点不同的是,利用AnimationDrawable实现动画时,本身并没有提供接口来监听动画的状态(开始,结束),需要自己处理。

关键字: oneshot  :表示是否只持续一次,duration持续时间,drawable图片。容易oom


Property Animation:

本篇文章分如下几个部分:

  • ObjectAnimator介绍
  • ValueAnimator介绍
  • TypeEvaluator(估值器)和TimeInterpolator(插值器)的学习

2、相关API

Property Animation故名思议就是通过动画的方式改变对象的属性了,我们首先需要了解几个属性:

Duration动画的持续时间,默认300ms。

Time interpolation:时间差值,乍一看不知道是什么,但是我说LinearInterpolator、AccelerateDecelerateInterpolator,大家一定知道是干嘛的了,定义动画的变化率。

Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。setRepeatCount()-1表示无限  setRepeatMode();

Animator sets: 动画集合,你可以定义一组动画,一起执行或者顺序执行。

Frame refresh delay:帧刷新延迟,对于你的动画,多久刷新一次帧;默认为10ms,但最终依赖系统的当前状态;基本不用管。

相关的类

ObjectAnimator  动画的执行类,后面详细介绍

addUpdateListener更新变化监听和addListener监听变化

ValueAnimator 动画的执行类,后面详细介绍 

AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。

AnimatorInflater 用户加载属性动画的xml文件

TypeEvaluator 类型估值,主要用于设置动画操作属性的值。

TimeInterpolator 时间插值,上面已经介绍。(计算执行到的占比时间,比如4秒执行到2秒,占比就是0.5)

1.ObjectAnimator介绍(记得Star)

ObjectAnimator类是我们在设计动画的时候经常需要使用到的类,它可以直接对任意对象的任意属性进行动画操作,ObjectAnimator提供静态的动画实现方法,具体的实现方法有如下几种:

下述的静态方法中,传入的参数一是目标View,参数二是进行改变的属性,参数三是变化的过程区间
请对照例子查看。

//颜色渐变动画
public static ObjectAnimator ofArgb(Object target, String propertyName, int... values)
//int类型值动画
public static ObjectAnimator ofInt(Object target, String propertyName, int... values)
//float类型值动画				(对象)(属性)(开始的,中间。。。,结束的属性值)
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)
//Object类型值动画
public static ObjectAnimator ofObject(Object target, String propertyName,        TypeEvaluator evaluator, Object... values)

....

对于ObjectAnimator

1、提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。

当对于属性值,只设置一个的时候,会认为当然对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束~~~

动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~

例如:

  1.     public void rotateyAnimRun(View view)  
  2.     {  
  3.          ObjectAnimator//  
  4.          .ofFloat(view, "rotationX"0.0F, 360.0F)//  
  5.          .setDuration(500)//  
  6.          .start();  
  7.     } 

ObjectAnimator提供了不少方法设计动画的执行过程,下面举出常用的一些方法:

//设置动画执行时长
setDuration(4000);
//设置动画监听
objectAnimator.addListener(new Animator.AnimatorListener() {  
  @Override   
 public void onAnimationStart(Animator animation) { 
           }   
     @Override  
  public void onAnimationEnd(Animator animation) {  
  }    
    @Override  
  public void onAnimationCancel(Animator animation) {   
 }    
    @Override
    public void onAnimationRepeat(Animator animation) { 
   }});
//设置动画循环播放的次数,默认为0,-1表示无限循环。
setRepeatCount();
//循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示连续重新播放和倒序播放的意思
setRepeatMode();

AnimatorSet:动画集合  既可以依次播放,也可以一起播放,可以定义各个动画的播放顺序

关于AnimatorSet的使用,有如下主要几个常用的方法:

after(Animator anim)   将现有动画插入到传入的动画之后执行
after(long delay)   将现有动画延迟指定毫秒后执行
before(Animator anim)   将现有动画插入到传入的动画之前执行
with(Animator anim)   将现有动画和传入的动画同时执行
playTogether(Animator... items)将所有传入动画同时执行
playSequentially(Animator... items)所有动画依次执行,//play执行一个
如:

float x=view.getTranslationX();
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "translationX",x,500,x );
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0f, 1f);
AnimatorSet animatorSet=new AnimatorSet();
animatorSet.playTogether(objectAnimator,objectAnimator2);
animatorSet.setDuration(5000);
animatorSet.start();//setStardelay()延迟播放
  • 4、ValueAnimator实现动画

和ObjectAnimator用法很类似,简单看一下用view垂直移动的动画代码:

[java]  view plain  copy
  1. public void verticalRun(View view)  
  2.     {  
  3.         ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight  
  4.                 - mBlueBall.getHeight());  
  5.         animator.setTarget(mBlueBall);  
  6.         animator.setDuration(1000).start();  
  7.     }  
这就是和ObjectAnimator的区别之处:ValueAnimator并没有在属性上做操作

好处:不需要操作的对象的属性一定要有getter和setter方法,你可以自己根据当前动画的计算值,来操作任何属性

demo
  1. /** 
  2.      * 自由落体 
  3.      * @param view 
  4.      */  
  5.     public void verticalRun( View view)  
  6.     {  
  7.         ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight  
  8.                 - mBlueBall.getHeight());  
  9.         animator.setTarget(mBlueBall);  
  10.         animator.setDuration(1000).start();  
  11. //      animator.setInterpolator(value)  
  12.         animator.addUpdateListener(new AnimatorUpdateListener()  
  13.         {  
  14.             @Override  
  15.             public void onAnimationUpdate(ValueAnimator animation)  
  16.             {  
  17.                 mBlueBall.setTranslationY((Float) animation.getAnimatedValue());  //getAnimatedValue获得是类型估值器执行Evaluator后的结果
  18.             }  
  19.         });  
  20.     } 
5、监听动画的事件

对于动画,一般都是一些辅助效果,比如我要删除个元素,我可能希望是个淡出的效果,但是最终还是要删掉,并不是你透明度没有了,还占着位置,所以我们需要知道动画如何结束。

所以我们可以添加一个动画的监听:

[java]  view plain  copy
  1. public void fadeOut(View view)  
  2.     {  
  3.         ObjectAnimator anim = ObjectAnimator.ofFloat(mBlueBall, "alpha"0.5f);  
  4.           
  5.         anim.addListener(new AnimatorListener()  
  6.         {  
  7.   
  8.             @Override  
  9.             public void onAnimationStart(Animator animation)  
  10.             {  
  11.                 Log.e(TAG, "onAnimationStart");  
  12.             }  
  13.   
  14.             @Override  
  15.             public void onAnimationRepeat(Animator animation)  
  16.             {  
  17.                 // TODO Auto-generated method stub  
  18.                 Log.e(TAG, "onAnimationRepeat");  
  19.             }  
  20.   
  21.             @Override  
  22.             public void onAnimationEnd(Animator animation)  
  23.             {  
  24.                 Log.e(TAG, "onAnimationEnd");  
  25.                 ViewGroup parent = (ViewGroup) mBlueBall.getParent();  
  26.                 if (parent != null)  
  27.                     parent.removeView(mBlueBall);  
  28.             }  
  29.   
  30.             @Override  
  31.             public void onAnimationCancel(Animator animation)  
  32.             {  
  33.                 // TODO Auto-generated method stub  
  34.                 Log.e(TAG, "onAnimationCancel");  
  35.             }  
  36.         });  
  37.         anim.start();  
  38.     }  

这样就可以监听动画的开始、结束、被取消、重复等事件~但是有时候会觉得,我只要知道结束就行了,这么长的代码我不能接收,那你可以使用AnimatorListenerAdapter

[java]  view plain  copy
  1. anim.addListener(new AnimatorListenerAdapter()  
  2. {  
  3.     @Override  
  4.     public void onAnimationEnd(Animator animation)  
  5.     {  
  6.         Log.e(TAG, "onAnimationEnd");  
  7.         ViewGroup parent = (ViewGroup) mBlueBall.getParent();  
  8.         if (parent != null)  
  9.             parent.removeView(mBlueBall);  
  10.     }  
  11. });  
TimeInterpolator(插值器)

TimeInterpolator中文译为时间插值器, 他的作用是根据时间流逝的百分比来计算出当前属性改变的百分比 ,系统中有预置的三种插值器:
  • LinearInterpolator(线性插值器),匀速的动画
  • DecelerateInterpolator(减速插值器),动画越来越慢
  • AccelerateDecelerateInterpolator(加速减速插值器),两头慢中间快
TypeEvaluator(估值器)
TypeEvaluator作用是 根据当前属性改变的百分比来计算改变后的属性值 ,其是要跟TimeInterpolator配对使用的。android内置的估值器有:
  • IntEvaluator Int类型估值器,返回int类型的属性改变
  • FloatEvaluator Float类型估值器,返回Float类型属性改变
  • ArgbEvaluator 颜色类型估值器

TypeEvaluator源码:

public interface TypeEvaluator<T> {  
  public T evaluate(float fraction, T startValue, T endValue);
}

evaluate()方法当中传入了三个参数,第一个参数fraction非常重要,这个参数用于表示动画的完成度的,我们应该根据它来计算当前动画的值应该是多少,第二第三个参数分别表示动画的初始值和结束值

下面以匀速动画实现过程来研究估值器和插值器在其中所扮演的角色,关于匀速动画实现的插值器源码和估值器源码如下所示:

时间插值器

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {  
 public LinearInterpolator() {    }   
 public LinearInterpolator(Context context, AttributeSet attrs) {    }   
 public float getInterpolation(float input) {        return input;    }  
      /** @hide */   
     @Override    
 public long createNativeInterpolator() {       
       return NativeInterpolatorFactoryHelper.createLinearInterpolator();    
  }
}

类型估值器
public class IntEvaluator implements TypeEvaluator<Integer> {    
  public Integer evaluate(float fraction, Integer startValue, Integer endValue) {     
     int startInt = startValue;    
     return (int)(startInt + fraction * (endValue - startInt));   
 }

比如一个移动的线性动画需要在1s中完成400dp的移动过程,那么在0.4s时候,时间插值器的值是多少呢,主要是看其getInterpolation()方法,我们可以看到,过了0.4s,流逝的时间比即是0.4/1=0.4,所以属性改变百分比的值为0.4,然后交付给估值器(这里假设使用Int类型估值器)进行对当前对象属性的改变操作。估值器获取到当前属性改变的百分比0.4后,在IntEvaluator中会将第一个参数赋值为0.4,计算得到结果后在进行属性的改变,当前过程会一直重复,知道动画完成为止。

demo:

下面再来一个例子,如果我希望小球抛物线运动【实现抛物线的效果,水平方向100px/s,垂直方向加速度200px/s*s 】,分析一下,貌似只和时间有关系,但是根据时间的变化,横向和纵向的移动速率是不同的,我们该咋实现呢?此时就要重写TypeValue的时候了,因为我们在时间变化的同时,需要返回给对象两个值,x当前位置,y当前位置:

代码:

[java]  view plain  copy
  1. /** 
  2.      * 抛物线 
  3.      * @param view 
  4.      */  
  5.     public void paowuxian(View view)  
  6.     {  
  7.   
  8.         ValueAnimator valueAnimator = new ValueAnimator();  
  9.         valueAnimator.setDuration(3000);  
  10.         valueAnimator.setObjectValues(new PointF(00));  
  11.         valueAnimator.setInterpolator(new LinearInterpolator());  
  12.         valueAnimator.setEvaluator(new TypeEvaluator<PointF>()  
  13.         {  
  14.             // fraction = t / duration  
  15.             @Override  
  16.             public PointF evaluate(float fraction, PointF startValue,  
  17.                     PointF endValue)  
  18.             {  
  19.                 Log.e(TAG, fraction * 3 + "");  
  20.                 // x方向200px/s ,则y方向0.5 * 10 * t  
  21.                 PointF point = new PointF();  
  22.                 point.x = 200 * fraction * 3;  
  23.                 point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);  
  24.                 return point;  
  25.             }  
  26.         });  
  27.   
  28.         valueAnimator.start();  
  29.         valueAnimator.addUpdateListener(new AnimatorUpdateListener()  
  30.         {  
  31.             @Override  
  32.             public void onAnimationUpdate(ValueAnimator animation)  
  33.             {  
  34.                 PointF point = (PointF) animation.getAnimatedValue();  
  35.                 mBlueBall.setX(point.x);  
  36.                 mBlueBall.setY(point.y);  
  37.   
  38.             }  
  39.         });  
  40.     }  
其他
1、如何使用xml文件来创建属性动画

大家肯定都清楚,View Animator 、Drawable Animator都可以在anim文件夹下创建动画,然后在程序中使用,甚至在Theme中设置为属性值。当然了,属性动画其实也可以在文件中声明:

首先在res下建立animator文件夹,然后建立res/animator/scalex.xml

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:duration="1000"  
  4.     android:propertyName="scaleX"  
  5.     android:valueFrom="1.0"  
  6.     android:valueTo="2.0"  
  7.     android:valueType="floatType" >  
  8. </objectAnimator>  
代码:

[java]  view plain  copy
  1. public void scaleX(View view)  
  2.     {  
  3.         // 加载动画  
  4.         Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex);  
  5.         anim.setTarget(mMv);  
  6.         anim.start();  
  7.     }  
使用AnimatorInflater加载动画的资源文件,然后设置目标,就ok~~是不是很简单,这只是单纯横向的放大一倍~

如果我希望纵向与横向同时缩放呢?则可以怎么定义属性文件:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:ordering="together" >  
  4.   
  5.     <objectAnimator  
  6.         android:duration="1000"  
  7.         android:propertyName="scaleX"  
  8.         android:valueFrom="1"  
  9.         android:valueTo="0.5" >  
  10.     </objectAnimator>  
  11.     <objectAnimator  
  12.         android:duration="1000"  
  13.         android:propertyName="scaleY"  
  14.         android:valueFrom="1"  
  15.         android:valueTo="0.5" >  
  16.     </objectAnimator>  
  17.   
  18. </set>  
使用set标签,有一个orderring属性设置为together,【还有另一个值:sequentially(表示一个接一个执行)】。
问题与解决:

在写一个小动画时发现AnimatorSet没有setRepeatCount()与setRepeatMode()方法,但是动画效果又要求重复执行,这里提供的解决方法时:
给动画集合中的子动画设置setRepeatCount(),想重复执行多少次动画就设置多少次,如果想无限循环,这里直接设置int的最大值应该就可以了(虽然感觉不是太好,但是正常情况下,一个动画也不会执行这么多次吧)。


[java]  view plain  copy
  1. ObjectAnimator animtion1=ObjectAnimator.ofFloat(mIvLine, "translationX"820);  
  2.        animtion1.setRepeatCount(1000);  
  3.        animtion1.setRepeatMode(ValueAnimator.INFINITE);  
  4.        ObjectAnimator animtion2=ObjectAnimator.ofFloat(mIvLine, "translationY",2030);  
  5.        animtion2.setRepeatCount(1000);  
  6.   
  7.        ObjectAnimator animtion3=ObjectAnimator.ofFloat(mIvLine, "rotation"3060);  
  8.        animtion3.setRepeatCount(1000);  
  9.        ObjectAnimator animtion5=ObjectAnimator.ofFloat(mIvLine, "translationX"200);  
  10.        animtion5.setRepeatCount(1000);  
  11.        ObjectAnimator animtion6=ObjectAnimator.ofFloat(mIvLine, "translationY"300);  
  12.        animtion6.setRepeatCount(1000);  
  13.        ObjectAnimator animtion4=ObjectAnimator.ofFloat(mIvLine, "rotation"6030);  
  14.        animtion4.setRepeatCount(1000);  
  15.         AnimatorSet set=new AnimatorSet();  
  16.   
  17.        set.playTogether(animtion1,animtion2,animtion3,animtion4,animtion5,animtion6);  
  18.        set.setDuration(1300).start();  

参考:http://www.jianshu.com/p/2c9887fe8c6f

http://blog.csdn.net/lmj623565791/article/details/38067475/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值