Android全套动画使用技巧

移动开发 Android
Animation框架定义了透明度、旋转、缩放和位移几种常见的动画,控制的整个View,实现原理是每次绘制视图时View所在ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧。如果没有完成就继续调用invalidate()函数,启动下次绘制来驱动动画,从而完成整个动画的绘制。

Android全套动画使用技巧

【引自MrXI的博客】 一、Android View 动画框架

Animation框架定义了透明度、旋转、缩放和位移几种常见的动画,控制的整个View,实现原理是每次绘制视图时View所在ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧。如果没有完成就继续调用invalidate()函数,启动下次绘制来驱动动画,从而完成整个动画的绘制。

视图动画使用简单,效果丰富,它提供了AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation四种动画方式,并提供动画集合AnimationSet,混合使用多种动画。在Android3.0之前,视图动画一家独大,但随着Android3.0之后属性动画框架的推出,它的风光就大不如从前。相比属性动画,视图动画的一个非常大的缺陷就是不具备交互性,当某个元素发生视图动画后,其响应事件的位置还依然在动画前的地方,所以视图动画只能做普通的动画效果,避免交互的发生。但是它的优点也非常明显,即效率比较高且使用方便。

视图动画使用非常简单,不仅可以通过XML文件来描述一个动画过程,同样也可以使用代码来控制整个动画过程。

(1)、透明度动画

为视图增加透明度的变换动画。

  1. AlphaAnimation aa = new AlphaAnimation(0, 1); 
  2.  
  3. aa.setDuration(1000); 
  4.  
  5. view.startAnimation(aa);  

(2)、旋转动画

为视图增加旋转的变换动画。

  1. RotateAnimation ra = new RotateAnimation(0, 360, 100, 100); 
  2.  
  3. ra.setDuration(1000); 
  4.  
  5. view.startAnimation(ra);  

其参数分别为旋转的起始角度和旋转中心点的坐标,当然,可以通过设置参数来控制旋转动画的参考系,这里设置旋转动画的参考系为中心。

  1. RotateAnimation ra1 = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5F, RotateAnimation.RELATIVE_TO_SELF, 0.5F); 

(3)、位移动画

为视图移动时增加位移动画。

  1. TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300); 
  2.  
  3. ta.setDuration(1000); 
  4.  
  5. view.startAnimation(ta); 

(4)、缩放动画

为视图的缩放增加动画效果

  1. ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2); 
  2.  
  3. sa.setDuration(1000); 
  4.  
  5. view.startAnimation(sa);  

与旋转动画一样,缩放动画也可以设置罗芳的中心点,设置中心为自身中心效果

  1. ScaleAnimation sa1 = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F); 
  2.  
  3. sa1.setDuration(1000); 
  4.  
  5. view.startAnimation(sa1);  

(5)、动画集合

通过AnimationSet,可以将动画以组合的形式展现出来:

  1. AnimationSet as = new AnimationSet(true); 
  2.  
  3. as.setDuration(1000); 
  4.  
  5. AlphaAnimation aa = new AlphaAnimation(0, 1); 
  6.  
  7. aa.setDuration(1000); 
  8.  
  9. as.addAnimation(aa); 
  10.  
  11. RotateAnimation ra = new RotateAnimation(0, 360, 100, 100); 
  12.  
  13. ra.setDuration(1000); 
  14.  
  15. as.addAnimation(ra); 
  16.  
  17. TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300); 
  18.  
  19. ta.setDuration(1000); 
  20.  
  21. as.addAnimation(ta); 
  22.  
  23. ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2); 
  24.  
  25. sa.setDuration(1000); 
  26.  
  27. as.addAnimation(sa); 
  28.  
  29. view.startAnimation(as);  

可以直接拷贝运行代码看效果!

对于动画事件,Android也提供了对应的监听回调,代码:

  1. as.setAnimationListener(new Animation.AnimationListener() { 
  2.  
  3. @Override 
  4.  
  5. public void onAnimationStart(Animation animation) { 
  6.  
  7. //动画开始 
  8.  
  9.  
  10. @Override 
  11.  
  12. public void onAnimationEnd(Animation animation) { 
  13.  
  14. //动画结束 
  15.  
  16.  
  17. @Override 
  18.  
  19. public void onAnimationRepeat(Animation animation) { 
  20.  
  21. //动画重复 
  22.  
  23.  
  24. });  

二、属性动画

由于Android3.0之前已有的动画框架Animation存在一些局限性——动画改变的只是显示,并不能响应事件。因此在Android3.0之后,Google就提出了属性动画这样一个新的动画框架,实现更丰富的效果。

而在Animator框架中使用最多的就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性值,而使用多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(long frameDelay)设置动画帧之间的间隙时间。最重要的是,属性动画通过调用属性的get、set方法来真实地控制了一个View的属性值,因此强大的属性动画框架,基本可以实现所有的动画效果。

(1)、ObjectAnimator

ObjectAnimator是属性动画框架中最重要的实行类,创建一个ObjectAnimator只需要通过他的静态工厂类直接返回一个ObjectAnimator对象。参数包括一个对象和对象的属性名字,但这个属性也必须有get和set函数,内部会通过Java反射机制来调用set函数修改对象属性值。同样,你也可以调用setInterpolator设置相应的差值器。

接下来试想一下对一个Button添加一个平移动画,使用以前的动画框架平移后将不能触发点击事件,点击的有效区域仍然是原来的地方,点击移动后的地方是不会有点击事件发生的。而属性动画则不同,它真实地改变了一个View的属性,所以事件响应的区域也同样发生了改变,这时候点击移动后的按钮,就会响应点击事件了。

属性动画平移代码如下:

  1. ObjectAnimator animator = ObjectAnimator.ofFloat( 
  2.  
  3. imageView, 
  4.  
  5. "translationX"
  6.  
  7. 200F); 
  8.  
  9. animator.setDuration(300); 
  10.  
  11. animator.start();  

在使用ObjectAnimator的时候,有一点非常重要,那就是要操纵的属性必须具有get、set方法,不然ObjectAnimator就无法生效。下面是常用的属性:

  • translationX和translationY:这两个属性作为一种增量控制着View对象从它布局容器左上角坐标开始的位置。
  • rotation、rotationX和rotationY:这个三个属性控制View对象围绕支点进行2D和3D旋转。
  • scaleX和scaleY:这两个属性控制着View对象围绕他的支点进行2D缩放。
  • pivotX和pivotY:这两个属性控制着View对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认情况下,该支点的位置就是View对象的中心点。
  • x和y:这两个简单实用的属性,描述了View对象在它的容器中的最终位置,它是最初的左上角坐标和translationX、translationY值的累积和。
  • alpha:表示View对象的alpha透明度。默认值是1(不透明),0代表完全透明(不可见)。

根据以上得知视图动画所实现的动画效果,这里基本都已经包含了。

那么如果一个属性没有get、set方法,属性动画是不是就束手无策了呢?答案是否定的,Google在应用层提供了两种方案来解决这个问题,一个是通过自定义一个属性类或者包装类,来间接地给这个属性增加get、set方法;或者通过ValueAnimator来实现,ValueAnimator在后面的内容中讲到,这个先看看使用包装类的方法给一个属性增加get、set方法,代码如下:

  1. private static class WrapperView { 
  2.     private View mTarget; 
  3.  
  4.     public WrapperView(View mTarget) { 
  5.         this.mTarget = mTarget; 
  6.     } 
  7.  
  8.     public int getWidth() { 
  9.         return mTarget.getLayoutParams().width; 
  10.     } 
  11.  
  12.     public void setWidth(int width) { 
  13.         mTarget.getLayoutParams().width = width; 
  14.         mTarget.requestLayout(); 
  15.     } 
  16.  

通过以上代码,就跟一个属性包装了一层,并给它提供了get、set方法。使用时只需要操纵包装类就可以间接调用到get、set方法了,代码如下所示:

  1. WrapperView wrapperView = new WrapperView(view); 
  2.  
  3. ObjectAnimator.ofInt(wrapperView, "width", 500).setDuration(5000).start();  

(2)、PropertyValuesHolder

类似视图动画中的AnimationSet,在属性动画中,如果针对同一个对象的多个属性,要同时作用多种动画,可以使用PropertyValuesHolder来实现。比如平移动画,如果在平移的过程中同时改变X、Y轴的缩放,可以这样实现,代码:

  1. PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 300); 
  2.  
  3. PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); 
  4.  
  5. PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); 
  6.  
  7. ObjectAnimator.ofPropertyValuesHolder(pvh1, pvh2, pvh3).setDuration(1000).start();  

在代码中,分别使用PropertyValuesHolder 对象控制translationX、scaleX、scaleY这三个属性,最屌调用ObjectAnimator.ofPropertyValuesHolder方法实现多属性动画的共同作用,整个实现方法非常类似AnimatorSet使用。

(3)、ValueAnimator

ValueAnimator在属性动画中占用非常重要的地位,虽然不ObjectAnimator那样耀眼,但它却是属性动画的核心所在,ObjectAnimator也是继承自ValueAnimator。

  1. public final class ObjectAnimator extends ValueAnimator 

ValueAnimator本身不提供任何动画效果,它更像一个数值发生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程,ValueAnimator的一般使用方法:通常在ValueAnimator的AnimatorUpdateListener中监听数值的变换,完成动画的变换。

  1. ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100); 
  2.  
  3. valueAnimator.setTarget(imageView); 
  4.  
  5. valueAnimator.setDuration(1000).start(); 
  6.  
  7. valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
  8.  
  9. @Override 
  10.  
  11. public void onAnimationUpdate(ValueAnimator animation) { 
  12.  
  13.    Float value = (Float) animation.getAnimatedValue(); 
  14.  
  15.    } 
  16.  
  17. });  

(4)、动画事件的监听

一个完整的动画具有Start、Repeat、End、Cancel四个过程,通过Android提供了接口,很方便地监听到这四个事件:

  1. ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "alpha", 0.5F); 
  2. anim.addListener(new Animator.AnimatorListener() { 
  3.     @Override 
  4.     public void onAnimationStart(Animator animation) { 
  5.          
  6.     } 
  7.  
  8.     @Override 
  9.     public void onAnimationEnd(Animator animation) { 
  10.  
  11.     } 
  12.  
  13.     @Override 
  14.     public void onAnimationCancel(Animator animation) { 
  15.  
  16.     } 
  17.  
  18.     @Override 
  19.     public void onAnimationRepeat(Animator animation) { 
  20.  
  21.     } 
  22. }); 
  23. anim.start();  

大部分的时候只关心onAnimationEnd事件,所以Android也提供了一个AnimatorListenerAdapter来让我们选择必要的事件进行监听:

  1. anim.addListener(new AnimatorListenerAdapter() { 
  2.     @Override 
  3.     public void onAnimationEnd(Animator animation) { 
  4.         super.onAnimationEnd(animation); 
  5.     } 
  6. });  

(***nimatorSet

对于一个属性同时作用多个属性动画效果,前面已经使用PropertyValuesHolder实现了这样的效果。而AnimatorSet不仅能实现这样的效果,同时也能实现更为精确的顺序控制。同样是实现上面使用PropertyValuesHolder演示的那个动画效果,如果使用AnimatorSet来实现,那么代码如下:

  1. ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 300f); 
  2.  
  3. ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0f, 1f); 
  4.  
  5. ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, 0f, 1f); 
  6.  
  7. AnimatorSet animatorSet = new AnimatorSet(); 
  8.  
  9. animatorSet.setDuration(1000); 
  10.  
  11. animatorSet.playTogether(objectAnimator, objectAnimator1, objectAnimator2); 
  12.  
  13. animatorSet.start();  

在属性动画中,AnimatorSet正是通过playTogether()、playSquentially()、animSet.play().width()、defore()、after()这些方法来控制多个动画的协同工作方式,从而做到对动画播放顺序的精确控制。

(6)、在XML中使用属性动画

属性动画同视图动画一样,也可以直接写在XML文件中,代码:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2.  
  3. <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" 
  4.  
  5. android:duration="1000" 
  6.  
  7. android:propertyName="scaleX" 
  8.  
  9. android:valueFrom="1.0" 
  10.  
  11. android:valueTo="2.0" 
  12.  
  13. android:valueType="floatType"
  14.  
  15. </objectAnimator>  

前提使用XML定义属性动画XML文件一定要放在res/animator/filename.xml文件夹下面才能识别,否则不能识别。发现属性动画与视图动画在XML文件中的写法很相似。在程序中使用:

  1. Animator anim = AnimatorInflater.loadAnimator(this,R.animator.filename); 
  2.  
  3. anim.setTarget(view); 
  4.  
  5. anim.start();  

(7)、View的animate方法

在Android3.0之后,Google给View增加了animate方法来直接驱动属性动画,代码如下:

  1. imageView.animate() 
  2.         .alpha(0) 
  3.         .y(300) 
  4.         .setDuration(300) 
  5.         .withStartAction(new Runnable() { 
  6.             @Override 
  7.             public void run() { 
  8.  
  9.             } 
  10.         }) 
  11.         .withEndAction(new Runnable() { 
  12.             @Override 
  13.             public void run() { 
  14.                 runOnUiThread(new Runnable() { 
  15.                     @Override 
  16.                     public void run() { 
  17.                          
  18.                     } 
  19.                 }); 
  20.             } 
  21.         }).start();  

三、Android布局动画

布局动画是指作用在ViewGroup上,给ViewGroup增加View时添加一个动画过渡效果。最简单的布局动画是在ViewGroup的XML中,使用如下代码打开布局动画:

  1. android:animateLayoutChanges="true" 

通过以上设置,当ViewGroup添加到View时,子View会呈现逐渐显示的过渡效果,不过这个效果是Android默认的显示的过渡效果,无法使用自定义动画来替换这个效果。

还可以通过使用LayoutAnimatorController类自定义一个子View的过渡效果,添加一个视图动画,使得子View出现的时候有一个缩放的动画效果,代码:

  1. LinearLayout ll = (LinearLayout) findViewById(R.id.ll); 
  2. ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1); 
  3. sa.setDuration(2000); 
  4. //设置布局动画的显示 
  5. LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f); 
  6. //设置布局动画 
  7. ll.setLayoutAnimation(lac);  

LayoutAnimationController 的***个参数,是需要作用的动画,而第二个参数,则是每个子View显示的delay时间。当delay时间不为0时,可以设置子View显示的顺序。

  1. //顺序 
  2.  
  3. public static final int ORDER_NORMAL = 0; 
  4.  
  5. //随机 
  6.  
  7. public static final int ORDER_REVERSE = 1; 
  8.  
  9. //反序 
  10.  
  11. public static final int ORDER_RANDOM = 2;  

四、Interpolators——插值器

插值器是动画一个非常重要的概念,通过插值器Interpolators,可以定义动画变换速率,这一点非常类似物理中的加速度,起作用主要是控制目标变量的变化值进行对应的变化。

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

未完,待续。。。

五、开源代码库

***再分享一个自己积攒很久的代码库,只有你想不到,没有用不到的,欢迎star

https://github.com/xijiufu

由于github服务器在美国,有时访问很慢,还提供了开源中国地址库,2个仓库代码均同步更新:

http://git.oschina.net/xijiufu

责任编辑:庞桂玉 来源: MrXI的博客
相关推荐

2010-01-28 13:12:47

Android使用An

2010-01-25 10:46:29

Android Spi

2010-01-25 18:22:33

Android使用XM

2013-01-08 16:05:23

Android开发布局ViewStub

2016-10-24 14:53:30

Android app使用技巧

2014-07-15 10:23:10

Android补间动画

2009-09-22 12:59:58

ibmdwDojo

2009-12-25 10:11:46

WPF后台控制动画

2021-10-12 11:07:33

动画深度Android

2011-12-21 09:20:21

2017-04-05 14:22:06

NPM开发工具

2017-02-07 11:35:26

Android动画蜡烛动画

2010-01-27 14:01:19

Android命令行启

2023-06-02 22:36:02

鸿蒙弹簧动画曲线

2010-11-01 09:46:21

ViewAndroid

2010-01-27 10:21:00

Android菜单

2017-03-02 10:30:57

AndroidAndroid Stu技巧

2010-01-27 17:45:15

Android应用技巧

2009-06-18 15:33:40

2011-04-01 10:53:43

点赞
收藏

51CTO技术栈公众号