Android动画机制及其使用
作为交互的一部分,开发Android应用的时候时常会用到动画,这样可以使应用看起来不那么死板。某些较为特定的点击可以使用有趣的动画引起注意,进而可以获取更多的点击量。随着Android系统的不断完善,其动画机制也不断地改进,如早期的帧动画和补间动画,3.0之后加入属性动画,以及之后5.x加入的SVG矢量动画等。以下讲一些较为常用的动画实现方式,即帧动画、补间动画和属性动画。
逐帧动画(Frame Animation)
逐帧动画也称之为Drawable Animation,是通过一系列的图片按顺序播放使其连成动画,这里每一帧都有对应的图片。例如我需要将名字为“droidman01”到“droidman16”的16张图片连成帧动画动画,那么实现方式如下
XML中:
将每一帧的图片放入res的drawable中然后再res的anim中(没有则新建一个Directory命名为anim)或是Android Studio的drawable中新建一个动画XML文件,使用标签来定义各个帧动图片的顺序,通过标签来排列。
...
imageView.setImageResource(R.drawable.frameanim); AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable(); animationDrawable.start();
这里的oneshot表示是否只执行一次,为false则执行一次就结束动画,为true当然就是循环播放。android:duration则是该帧图片播放的持续时间。
java代码中:
AnimationDrawable animationDrawable = new AnimationDrawable(); for (int i = 1;i<16;i++){ int id; if (i<10){ id = getResources().getIdentifier("droidman0"+i,"drawable",getPackageName()); }else{ id = getResources().getIdentifier("droidman"+i,"drawable",getPackageName()); } Drawable drawable = getResources().getDrawable(id); animationDrawable.addFrame(drawable,150); } imageView.setImageDrawable(animationDrawable); animationDrawable.setOneShot(false); animationDrawable.start();
在这里会看到一个方法getIdentifier(),这个方法是用来获取资源id的。第一个参数是资源名,第二个参数是资源类型可以为null,第三个参数是包名,也可以为空。这个方法对于获取资源名称类似的很有用,很方便。这里通过addFrame方法传入每帧的图片,并设置播放时间,同样代码中可通过setOneShot方法设置是否循环播放,最后通过start()方法开始播放动画。除此之外AnimationDrawable还提供其他方法如:
stop():停止播放动画
isRunning():放回boolean类型表示动画是否正在播放中
run():继续从下一帧开始播放
getNumberOfFrames():获取总帧数
getFrame(int index):获取指定帧图片
getDuration(int i):获取指定帧播放时间
isOneShot():是否是一次播放
上面动画的效果:
补间动画(Twwen Animation)
补间动画无需定义每一帧,只需定义开始和结束的关键两帧,中间的变化可设置插值器(Interpolator)来平滑过渡。补间动画提供了四个基本类型的动画:AlphaAnimation、RotateAnimation、TranslateAnimation和ScaleAnimation。其实这些动画使用起来相对不难,只要知道各个参数的含义即可。一下就一一说明。
AlphaAnimation
// 参数分别为开始和结束时的透明度,参数的取值区间[0,1]的float类型,即全透明到完全不透明。 AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
RotateAnimation
// 两参数分别为动画开始时的旋转角度和动画结束时的旋转角度,以点(0,0)为中心旋转 RotateAnimation rotateAnimation1 = new RotateAnimation(0,360); // 旋转角度从0度到360度,旋转中心为点(100,100) RotateAnimation rotateAnimation2 = new RotateAnimation(0,360,100,100); // 旋转角度从0到360度。X轴方向上的旋转参考类型,相对参考类型的X坐标位置,Y轴方向上旋转的参考类型,相对参考类型的Y坐标位置, // 此处参考类型有RotateAnimation.RELATIVE_TO_SELF自身,RotateAnimation.ABSOLUTE绝对位置,RotateAnimation.RELATIVE_TO_PARENT父控件, // 如该写法为以自身的中心位置旋转 RotateAnimation rotateAnimation3 = new RotateAnimation(0,360,RotateAnimation.RELATIVE_TO_SELF,0.5F,RotateAnimation.RELATIVE_TO_SELF,0.5F);
TranslateAnimation
// 参数分别为动画开始X坐标,动画结束X坐标,动画开始Y坐标,动画结束X坐标。即动画效果是从(0,0)平移到(200,300)位置 TranslateAnimation translateAnimation1 = new TranslateAnimation(0,200,0,300); // 和旋转的一样,有着参考类型,该效果为从该控件的(0,0)开始到控件宽高的2倍位置 TranslateAnimation translateAnimation2 = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF,0F,TranslateAnimation.RELATIVE_TO_SELF,0F, TranslateAnimation.RELATIVE_TO_SELF,2F,TranslateAnimation.RELATIVE_TO_SELF,2F);
ScaleAnimation
// 参数分别为动画开始时的X轴坐标伸缩尺寸,动画结束时X轴伸缩尺寸,动画开始时Y轴伸缩尺寸,动画结束时Y轴伸缩尺寸。其中尺寸数值为该空间原始大小的倍数。 // 该效果为以点(0,0)开始向外放大2倍 ScaleAnimation scaleAnimation1 = new ScaleAnimation(0f,2f,0f,2f); // 前四个参数与上一样,后两个为缩放中心 ScaleAnimation scaleAnimation2 = new ScaleAnimation(0f,2f,0f,2f,100,200); // 前四个参数与上一样,后四个为参考类型和参考相对位置,如此效果为以自身中心X,Y轴都伸展为原来的2倍 ScaleAnimation scaleAnimation3 = new ScaleAnimation(0f,2f,0f,2f,ScaleAnimation.RELATIVE_TO_SELF,0.5F,ScaleAnimation.RELATIVE_TO_SELF,0.5F);
使用时只需设置动画时间即可开启动画,以透明动画为例,其他用法类似
//动画持续时间 alphaAnimation.setDuration(1000); //动画结束时保留状态 alphaAnimation.setFillAfter(true); //设置插值器 alphaAnimation.setInterpolator(new LinearInterpolator(); //开启动画 imageView.startAnimation(alphaAnimation);
动画叠加AnimationSet
AnimationSet animationSet = new AnimationSet(true); animationSet.setDuration(2000); animationSet.addAnimation(alphaAnimation); animationSet.addAnimation(rotateAnimation1); animationSet.addAnimation(translateAnimation1); animationSet.addAnimation(scaleAnimation1); imageView.startAnimation(animationSet);
通过AnimationSet的addAnimation方法可将各动画添加进来,然后设置时间即可。
动画监听
animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { // 动画开始时 } @Override public void onAnimationEnd(Animation animation) { // 动画结束时 } @Override public void onAnimationRepeat(Animation animation) { // 重复动画时 } });
我们常常会在动画执行的开始或者结束时做一些相应的操作,此时就会需要监听动画的执行过程。如一个动画之后执行另一个动画等。
属性动画(Property Animation)
Android 3.0之后引进了属性动画,相较于之前的动画,属性动画真实改变了View的属性,而之前的那两种动画则只是视图上的改变,其触发位置仍旧没有变化,因此属性动画更适合做一些需要交互较强的动画。
ObjectAnimator
属性动画常用到的一个类就是ObjectAnimator,它是属性动画中最重要的一个执行类,继承自属性动画中最重要的类ValueAnimator。ObjectAnimator使用起来也相对较方便,只要记得第二个参数所要执行的动画即可,因为这里所填的是第一个参数对象的属性,且这个属性必须有get、set方法。我们以一个简单的用法来说明
ObjectAnimator objectAnimator =ObjectAnimator.ofFloat(imageView,"translationX",-300,300); objectAnimator.setDuration(2000); // 设置播放次数。如果为ValueAnimator.INFINITE表示无限播放下去 objectAnimator.setRepeatCount(ValueAnimator.INFINITE); // 设置播放重复模式。RESTART表示重新开始动画,REVERSE表示动画反过来播放。 objectAnimator.setRepeatMode(ValueAnimator.REVERSE); objectAnimator.start();
通过ObjectAnimator的工厂方法创建对象,其中第一个参数是要操作的View,第二个参数是要操作的属性,第三个参数是对应的属性变化,其是一个可变数组,即后面可继续添加参数,如这个效果就是将imageView控件在X轴方向的位移。第三个参数及其之后的参数为关键转折点。重点说下第二个参数,我们对View的动画操作常用的有(即第二个参数的值):
pivotX和pivotY:设置View的支点位置,默认为View的中心点
translationX和translationY:View的X轴和Y轴的偏移量,或者说位移距离。
rotation、rotationX和rotationY:View围绕支点,分别以Z轴、X轴和Y轴旋转,其中Z轴垂直屏幕。
scaleX和scaleY:View以支点做缩放。
x和y:直接设置View的位置,相当于原位置移动x和y距离。
alpha:设置View的透明度,1不透明,0全透明。
那么之前所说的set和get和这些值有什么关系呢?我们会有这些值,是因为内部通过java反射机制来调用set函数修改对象的属性值,我们打开源码ImageView继承View,而View中有一系列的函数,即方法。我们可以发现这些可以改变View属性的方法,如setTranslationX/getTranslationX、setRotationX/getRotationX等,这才使得属性动画能够找到这些方法并对其属性值做更改。
PropertyValuesHolder
PropertyValuesHolder使用起来和ObjectAnimator一样,只是它可以通过ObjectAnimator的ofPropertyValuesHolder方法将各个效果叠加起来,和AnimationSet类似。其使用方法如下,效果是在移动同时进行缩放操作。
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX",200f); PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX",1f,0f,1f); PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY",1f,0f,1f); ObjectAnimator.ofPropertyValuesHolder(imageView,pvh1,pvh2,pvh3).setDuration(2000).start();
ValueAnimator
ValueAnimator是属性动画中最重要的一个类,继承自Animator。它定义了属性动画中大部分的功能,如计算各帧的属性值、处理更新事件、根据属性值得类型知道操作的属性对象而做相应的计算规则的控制。也就是说ValueAnimator其实本身不负责动画的执行,更重要的是动画执行过程中数据的获取。可以根据需要设置动画持续的时间、插值方式、重复次数等,然后启动动画。使用时一般需要注册AnimatorUpdateListener监听器。然后再监听器中获取实时数值,之后将得到的数值设置到需要的地方。用法大致如下:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100); valueAnimator.setTarget(imageView); valueAnimator.setDuration(2000); valueAnimator.start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Float value = (Float) animation.getAnimatedValue(); // TODO 使用获取来的值 } });
AnimatorSet
视图动画有同感AnimationSet将各个动画叠加,属性动画当然也有,那就是AnimatorSet,相较于之前的PropertyValuesHolder,AnimatorSet可以更好地控制各个动画的顺序,如用AnimatorSet实现如上面PropertyValuesHolder一样的动画效果
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView,"translationX",200f); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView,"scaleX",1f,0f,1f); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageView,"scaleY",1f,0f,1f); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(2000); animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3); animatorSet.start();
在此AnimatorSet还提供不同的方法来调整各个属性动画的顺序。如:
// 三个动画同时播放 animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3); // 三个动画按顺序播放 animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3); // objectAnimator1动画与objectAnimator2动画同时播放 animatorSet.play(objectAnimator1).with(objectAnimator2); // objectAnimator1动画在objectAnimator2动画播放之前进行,即先播放1动画再播放2动画 animatorSet.play(objectAnimator1).before(objectAnimator2); // objectAnimator1动画在objectAnimator2动画播放之后进行,即先播放2动画再播放1动画 animatorSet.play(objectAnimator1).after(objectAnimator2);
animate方法给View设置动画
在系统3.0之后,如果动画只执行一次,则可以考虑使用animate()方法来完成动画。即View调用animate()。其简单使用例子如下。
imageView.animate() .translationX(200f) .scaleX(2f).scaleY(2f) .setDuration(2000) .withStartAction(new Runnable() { @Override public void run() { // 动画开始 } }).withEndAction(new Runnable() { @Override public void run() { // 动画结束 runOnUiThread(new Runnable() { @Override public void run() { } }); } });
这里调用animate()方法实际是活的一个ViewPropertyAnimator对象,其实际也是属性动画。但这里的属性不是可变数组,且不能设置重复播放。因此用于简单动画叠加或者一次性播放的还是挺方便的。
动画事件的监听
在属性动画执行的过程中,如果需要在某个执行过程做其他操作,则需添加监听事件
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) { // 动画重复时 } });
如果只想单独监听某个事件则注册监听AnimatorListenerAdapter即可选择需要的事件对其进行监听。
objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationCancel(Animator animation) { super.onAnimationCancel(animation); } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } @Override public void onAnimationRepeat(Animator animation) { super.onAnimationRepeat(animation); } @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); } @Override public void onAnimationPause(Animator animation) { super.onAnimationPause(animation); } @Override public void onAnimationResume(Animator animation) { super.onAnimationResume(animation); } });
XML中定义属性动画
在res目录下创建anim或是animator文件夹,并新建一个根标签为objectAnimator的xml文件
在代码中使用
Animator animator = AnimatorInflater.loadAnimator(this,R.animator.objectanim); animator.setTarget(imageView); animator.start();
上一篇: python实现数据写入excel表格
下一篇: Android开发艺术探索阅后提炼