1、概述

Android提供了几种动画类型:View Animation 、Drawable Animation 、Property Animation 。View Animation相当简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画,且有一定的局限性。比如:你希望View有一个颜色的切换动画;你希望可以使用3D旋转动画;你希望当动画停止时,View的位置就是当前的位置;这些View Animation都无法做到。这就是Property Animation产生的原因,本篇博客详细介绍Property Animation的用法。至于Drawable Animation,嗯,略~

2、相关API

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

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

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

Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。

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

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

相关的类

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

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

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

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

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

TimeInterpolator 时间插值,上面已经介绍。

总的来说,属性动画就是,动画的执行类来设置动画操作的对象的属性、持续时间,开始和结束的属性值,时间差值等,然后系统会根据设置的参数动态的变化对象的属性。

3、ObjectAnimator实现动画

之所以选择ObjectAnimator为第一个~~是因为,这个实现最简单~~一行代码,秒秒钟实现动画,下面看个例子:
布局文件:

[html] view plain copy
  1. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:id="@+id/id_container">
  6. <ImageView
  7. android:id="@+id/id_ball"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_centerInParent="true"
  11. android:src="@drawable/mv"
  12. android:scaleType="centerCrop"
  13. android:onClick="rotateyAnimRun"
  14. />
  15. </RelativeLayout>

很简单,就一张妹子图片~
Activity代码:

[java] view plain copy
  1. packagecom.example.zhy_property_animation;
  2. importandroid.animation.ObjectAnimator;
  3. importandroid.app.Activity;
  4. importandroid.os.Bundle;
  5. importandroid.view.View;
  6. publicclassObjectAnimActivityextendsActivity
  7. {
  8. @Override
  9. protectedvoidonCreate(BundlesavedInstanceState)
  10. {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.xml_for_anim);
  13. }
  14. publicvoidrotateyAnimRun(Viewview)
  15. {
  16. ObjectAnimator//
  17. .ofFloat(view,"rotationX",0.0F,360.0F)//
  18. .setDuration(500)//
  19. .start();
  20. }
  21. }

效果:

Android 属性动画(Property Animation) 完全解析_第1张图片

是不是一行代码就能实现简单的动画~~

对于ObjectAnimator

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

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

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

2、如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。

[java] view plain copy
  1. anim.addUpdateListener(newAnimatorUpdateListener()
  2. {
  3. @Override
  4. publicvoidonAnimationUpdate(ValueAnimatoranimation)
  5. {
  6. //view.postInvalidate();
  7. //view.invalidate();
  8. }
  9. });
3、看了上面的例子,因为设置的操作的属性只有一个,那么如果我希望一个动画能够让View既可以缩小、又能够淡出(3个属性scaleX,scaleY,alpha),只使用ObjectAnimator咋弄?

想法是不是很不错,可能会说使用AnimatorSet啊,这一看就是一堆动画塞一起执行,但是我偏偏要用一个ObjectAnimator实例实现呢~下面看代码:

[java] view plain copy
  1. publicvoidrotateyAnimRun(finalViewview)
  2. {
  3. ObjectAnimatoranim=ObjectAnimator//
  4. .ofFloat(view,"zhy",1.0F,0.0F)//
  5. .setDuration(500);//
  6. anim.start();
  7. anim.addUpdateListener(newAnimatorUpdateListener()
  8. {
  9. @Override
  10. publicvoidonAnimationUpdate(ValueAnimatoranimation)
  11. {
  12. floatcVal=(Float)animation.getAnimatedValue();
  13. view.setAlpha(cVal);
  14. view.setScaleX(cVal);
  15. view.setScaleY(cVal);
  16. }
  17. });
  18. }

把设置属性的那个字符串,随便写一个该对象没有的属性,就是不管~~咱们只需要它按照时间插值和持续时间计算的那个值,我们自己手动调用~

效果:

Android 属性动画(Property Animation) 完全解析_第2张图片

这个例子就是想说明一下,有时候换个思路不要被API所约束,利用部分API提供的功能也能实现好玩的效果~~~

比如:你想实现抛物线的效果,水平方向100px/s,垂直方向加速度200px/s*s ,咋实现呢~~可以自己用ObjectAnimator试试~

4、其实还有更简单的方式,实现一个动画更改多个效果:使用propertyValuesHolder

[java] view plain copy
  1. publicvoidpropertyValuesHolder(Viewview)
  2. {
  3. PropertyValuesHolderpvhX=PropertyValuesHolder.ofFloat("alpha",1f,
  4. 0f,1f);
  5. PropertyValuesHolderpvhY=PropertyValuesHolder.ofFloat("scaleX",1f,
  6. 0,1f);
  7. PropertyValuesHolderpvhZ=PropertyValuesHolder.ofFloat("scaleY",1f,
  8. 0,1f);
  9. ObjectAnimator.ofPropertyValuesHolder(view,pvhX,pvhY,pvhZ).setDuration(1000).start();
  10. }


4、ValueAnimator实现动画

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

[java] view plain copy
  1. publicvoidverticalRun(Viewview)
  2. {
  3. ValueAnimatoranimator=ValueAnimator.ofFloat(0,mScreenHeight
  4. -mBlueBall.getHeight());
  5. animator.setTarget(mBlueBall);
  6. animator.setDuration(1000).start();
  7. }

给你的感觉是不是,坑爹啊,这和ValueAnimator有毛线区别~但是仔细看,你看会发现,没有设置操作的属性~~也就是说,上述代码是没有任何效果的,没有指定属性~

这就是和ValueAnimator的区别之处:ValueAnimator并没有在属性上做操作,你可能会问这样有啥好处?我岂不是还得手动设置?

好处:不需要操作的对象的属性一定要有getter和setter方法,你可以自己根据当前动画的计算值,来操作任何属性,记得上例的那个【我希望一个动画能够让View既可以缩小、又能够淡出(3个属性scaleX,scaleY,alpha)】吗?其实就是这么个用法~

实例:

布局文件:

[html] view plain copy
  1. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:id="@+id/id_container"
  6. >
  7. <ImageView
  8. android:id="@+id/id_ball"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:src="@drawable/bol_blue"/>
  12. <LinearLayout
  13. android:layout_width="fill_parent"
  14. android:layout_height="wrap_content"
  15. android:layout_alignParentBottom="true"
  16. android:orientation="horizontal">
  17. <Button
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:onClick="verticalRun"
  21. android:text="垂直"/>
  22. <Button
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:onClick="paowuxian"
  26. android:text="抛物线"/>
  27. </LinearLayout>
  28. </RelativeLayout>
左上角一个小球,底部两个按钮~我们先看一个自由落体的代码:

[java] view plain copy
  1. /**
  2. *自由落体
  3. *@paramview
  4. */
  5. publicvoidverticalRun(Viewview)
  6. {
  7. ValueAnimatoranimator=ValueAnimator.ofFloat(0,mScreenHeight
  8. -mBlueBall.getHeight());
  9. animator.setTarget(mBlueBall);
  10. animator.setDuration(1000).start();
  11. //animator.setInterpolator(value)
  12. animator.addUpdateListener(newAnimatorUpdateListener()
  13. {
  14. @Override
  15. publicvoidonAnimationUpdate(ValueAnimatoranimation)
  16. {
  17. mBlueBall.setTranslationY((Float)animation.getAnimatedValue());
  18. }
  19. });
  20. }

与ObjectAnimator不同的就是我们自己设置元素属性的更新~虽然多了几行代码,但是貌似提高灵活性~

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

代码:

[java] view plain copy
  1. /**
  2. *抛物线
  3. *@paramview
  4. */
  5. publicvoidpaowuxian(Viewview)
  6. {
  7. ValueAnimatorvalueAnimator=newValueAnimator();
  8. valueAnimator.setDuration(3000);
  9. valueAnimator.setObjectValues(newPointF(0,0));
  10. valueAnimator.setInterpolator(newLinearInterpolator());
  11. valueAnimator.setEvaluator(newTypeEvaluator<PointF>()
  12. {
  13. //fraction=t/duration
  14. @Override
  15. publicPointFevaluate(floatfraction,PointFstartValue,
  16. PointFendValue)
  17. {
  18. Log.e(TAG,fraction*3+"");
  19. //x方向200px/s,则y方向0.5*10*t
  20. PointFpoint=newPointF();
  21. point.x=200*fraction*3;
  22. point.y=0.5f*200*(fraction*3)*(fraction*3);
  23. returnpoint;
  24. }
  25. });
  26. valueAnimator.start();
  27. valueAnimator.addUpdateListener(newAnimatorUpdateListener()
  28. {
  29. @Override
  30. publicvoidonAnimationUpdate(ValueAnimatoranimation)
  31. {
  32. PointFpoint=(PointF)animation.getAnimatedValue();
  33. mBlueBall.setX(point.x);
  34. mBlueBall.setY(point.y);
  35. }
  36. });
  37. }
可以看到,因为ofInt,ofFloat等无法使用,我们自定义了一个TypeValue,每次根据当前时间返回一个PointF对象,(PointF和Point的区别就是x,y的单位一个是float,一个是int;RectF,Rect也是)PointF中包含了x,y的当前位置~然后我们在监听器中获取,动态设置属性:

效果图:

Android 属性动画(Property Animation) 完全解析_第3张图片

有木有两个铁球同时落地的感觉~~对,我应该搞两个球~~ps:物理公式要是错了,就当没看见哈

自定义TypeEvaluator传入的泛型可以根据自己的需求,自己设计个Bean。

好了,我们已经分别讲解了ValueAnimator和ObjectAnimator实现动画;二者区别;如何利用部分API,自己更新属性实现效果;自定义TypeEvaluator实现我们的需求;但是我们并没有讲如何设计插值,其实我觉得把,这个插值默认的那一串实现类够用了~~很少,会自己去设计个超级变态的~嗯~所以:略。

5、监听动画的事件

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

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

[java] view plain copy
  1. publicvoidfadeOut(Viewview)
  2. {
  3. ObjectAnimatoranim=ObjectAnimator.ofFloat(mBlueBall,"alpha",0.5f);
  4. anim.addListener(newAnimatorListener()
  5. {
  6. @Override
  7. publicvoidonAnimationStart(Animatoranimation)
  8. {
  9. Log.e(TAG,"onAnimationStart");
  10. }
  11. @Override
  12. publicvoidonAnimationRepeat(Animatoranimation)
  13. {
  14. //TODOAuto-generatedmethodstub
  15. Log.e(TAG,"onAnimationRepeat");
  16. }
  17. @Override
  18. publicvoidonAnimationEnd(Animatoranimation)
  19. {
  20. Log.e(TAG,"onAnimationEnd");
  21. ViewGroupparent=(ViewGroup)mBlueBall.getParent();
  22. if(parent!=null)
  23. parent.removeView(mBlueBall);
  24. }
  25. @Override
  26. publicvoidonAnimationCancel(Animatoranimation)
  27. {
  28. //TODOAuto-generatedmethodstub
  29. Log.e(TAG,"onAnimationCancel");
  30. }
  31. });
  32. anim.start();
  33. }

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

[java] view plain copy
  1. anim.addListener(newAnimatorListenerAdapter()
  2. {
  3. @Override
  4. publicvoidonAnimationEnd(Animatoranimation)
  5. {
  6. Log.e(TAG,"onAnimationEnd");
  7. ViewGroupparent=(ViewGroup)mBlueBall.getParent();
  8. if(parent!=null)
  9. parent.removeView(mBlueBall);
  10. }
  11. });

AnimatorListenerAdapter继承了AnimatorListener接口,然后空实现了所有的方法~

效果图:

Android 属性动画(Property Animation) 完全解析_第4张图片

animator还有cancel()和end()方法:cancel动画立即停止,停在当前的位置;end动画直接到最终状态。

6、AnimatorSet的使用

实例:

布局文件:

[html] view plain copy
  1. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:id="@+id/id_container"
  6. >
  7. <ImageView
  8. android:id="@+id/id_ball"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:layout_centerInParent="true"
  12. android:src="@drawable/bol_blue"/>
  13. <LinearLayout
  14. android:layout_width="fill_parent"
  15. android:layout_height="wrap_content"
  16. android:layout_alignParentBottom="true"
  17. android:orientation="horizontal">
  18. <Button
  19. android:layout_width="wrap_content"
  20. android:layout_height="wrap_content"
  21. android:onClick="togetherRun"
  22. android:text="简单的多动画Together"/>
  23. <Button
  24. android:layout_width="wrap_content"
  25. android:layout_height="wrap_content"
  26. android:onClick="playWithAfter"
  27. android:text="多动画按次序执行"/>
  28. </LinearLayout>
  29. </RelativeLayout>

继续玩球~

代码:

[java] view plain copy
  1. packagecom.example.zhy_property_animation;
  2. importandroid.animation.AnimatorSet;
  3. importandroid.animation.ObjectAnimator;
  4. importandroid.app.Activity;
  5. importandroid.os.Bundle;
  6. importandroid.view.View;
  7. importandroid.view.animation.LinearInterpolator;
  8. importandroid.widget.ImageView;
  9. publicclassAnimatorSetActivityextendsActivity
  10. {
  11. privateImageViewmBlueBall;
  12. @Override
  13. protectedvoidonCreate(BundlesavedInstanceState)
  14. {
  15. super.onCreate(savedInstanceState);
  16. setContentView(R.layout.anim_set);
  17. mBlueBall=(ImageView)findViewById(R.id.id_ball);
  18. }
  19. publicvoidtogetherRun(Viewview)
  20. {
  21. ObjectAnimatoranim1=ObjectAnimator.ofFloat(mBlueBall,"scaleX",
  22. 1.0f,2f);
  23. ObjectAnimatoranim2=ObjectAnimator.ofFloat(mBlueBall,"scaleY",
  24. 1.0f,2f);
  25. AnimatorSetanimSet=newAnimatorSet();
  26. animSet.setDuration(2000);
  27. animSet.setInterpolator(newLinearInterpolator());
  28. //两个动画同时执行
  29. animSet.playTogether(anim1,anim2);
  30. animSet.start();
  31. }
  32. publicvoidplayWithAfter(Viewview)
  33. {
  34. floatcx=mBlueBall.getX();
  35. ObjectAnimatoranim1=ObjectAnimator.ofFloat(mBlueBall,"scaleX",
  36. 1.0f,2f);
  37. ObjectAnimatoranim2=ObjectAnimator.ofFloat(mBlueBall,"scaleY",
  38. 1.0f,2f);
  39. ObjectAnimatoranim3=ObjectAnimator.ofFloat(mBlueBall,
  40. "x",cx,0f);
  41. ObjectAnimatoranim4=ObjectAnimator.ofFloat(mBlueBall,
  42. "x",cx);
  43. /**
  44. *anim1,anim2,anim3同时执行
  45. *anim4接着执行
  46. */
  47. AnimatorSetanimSet=newAnimatorSet();
  48. animSet.play(anim1).with(anim2);
  49. animSet.play(anim2).with(anim3);
  50. animSet.play(anim4).after(anim3);
  51. animSet.setDuration(1000);
  52. animSet.start();
  53. }
  54. }

写了两个效果:

第一:使用playTogether两个动画同时执行,当然还有playSequentially依次执行~~

第二:如果我们有一堆动画,如何使用代码控制顺序,比如1,2同时;3在2后面;4在1之前等~就是效果2了

有一点注意:animSet.play().with();也是支持链式编程的,但是不要想着狂点,比如 animSet.play(anim1).with(anim2).before(anim3).before(anim5); 这样是不行的,系统不会根据你写的这一长串来决定先后的顺序,所以麻烦你按照上面例子的写法,多写几行:

效果图:

Android 属性动画(Property Animation) 完全解析_第5张图片


好了,由于篇幅~~关于属性动画还有点知识:

1、xml文件创建属性动画

2、布局动画

3、View的animate方法等。

那就考虑写到下一篇了,不过核心的功能就这些了~~

对了,如果使用11以下的SDK ,请导入nineoldandroids动画库,用法基本完全一致~


欢迎大家加入android开发交流群:454430053



更多相关文章

  1. TextView支持的XML属性及相关方法
  2. android 动画Animation属性大全(-)
  3. Android RecyclerView 实现瀑布流交错效果,并使最后一行子View高
  4. React Native Android ScrollView 去除阴影效果
  5. Android矢量图(二)--VectorDrawable所有属性全解析
  6. 2014-11-6Android学习------Android 仿真翻页效果实现--------贝
  7. Android清单文件详解(六) ---- 节点的属性
  8. Android仿IOS回弹效果 ScrollView回弹 总结
  9. android Kotlin 继承、派生、接口、构造方式,方法、属性重写

随机推荐

  1. Android对话框
  2. Android(安卓)输入手机号有空格
  3. 为TabLayout设置自定义布局
  4. android 网站
  5. android 创建自定义对话框
  6. Android模拟点击,getevent,sendevent重现
  7. Android(安卓)工具代码
  8. Android(安卓)获取播放视频的相关 内容,
  9. android 添加,删除程序
  10. Android中隐藏标题栏和状态栏