解析Android中Animation动画的编写要点
在API Demo的View->Animation下可以找到四个Animation的Demo,第一个3D Translate比较复杂,最后再讲,先讲第2个Interpolator。该Activity对应的是view包内的Animation3.java,和layout的animation_3.xml。
界面的布局不加解释了,就一个Spinner和一个TextView。不是本文内容。
主要解释下几个重点语句。
初始化Animation,从类的名字可以看出是一个变换View的位置的动画,参数起点横坐标,终点横坐标,起点纵坐标,终点纵坐标。
Animation a = new TranslateAnimation(0.0f, targetParent.getWidth() - target.getWidth() - targetParent.getPaddingLeft() - targetParent.getPaddingRight(), 0.0f, 0.0f);
下面是动画的参数设置,我加上了注释
a.setDuration(1000);//设置动画所用的时间 a.setStartOffset(300);//设置动画启动的延时 //设置重复模式,RESTART为结束后重新开始,REVERSE为按原来的轨迹逆向返回 a.setRepeatMode(Animation.RESTART); //设置重复次数,INFINITE为无限 a.setRepeatCount(Animation.INFINITE); //根据用户在Spinner的选择设置target的进入的方式 switch (position) { case 0: //加速进入 a.setInterpolator(AnimationUtils.loadInterpolator(this.R.anim.accelerate_interpolator)); break; case 1: //减速进入 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.decelerate_interpolator)); break; case 2: //加速进入.与第一个的区别为当repeatMode为reverse时,仍为加速返回原点 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.accelerate_decelerate_interpolator)); break; case 3: //先往后退一点再加速前进 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.anticipate_interpolator)); break; case 4: //减速前进,冲过终点前再后退 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.overshoot_interpolator)); break; case 5: //case 3,4的结合体 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.anticipate_overshoot_interpolator)); break; case 6: //停止前来回振几下 a.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.bounce_interpolator)); break; } //让target开始执行这个动画 target.startAnimation(a); }
这里使用的是Android已预设的一些动作,我们也可以自定义XML来实现更好看的动画效果的,这个下一篇再讲。
除了TranslationAnimation,还有AlphaAnimation、RotateAnimation、ScaleAnimation,使用这几个基体动作的组合,可以形成一系列复杂的动画效果。具体用法请查看SDK。
整个都比较简单,就一个函数的调用,还不懂的看一下API的注释和SDK文档,没什么难理解的。
现在开始看第三个Push,从View->animation->Push可以启动这个Activity
Push这个Demo主要是展示了View之间的切换效果。
Push对应的Java文件为view包内的Animation2.java,对应的XML布局文件为layout/animation_2.xml。
先看布局文件,这个页面内最主要用到的是一个ViewFlipper。使用ViewFlipper可以实现多个View之间的动态切换,并且可以自定义切换动画,本例中所展示的就是如何定义切换动画。
下面只挑重点语句来讲了。
让ViewFlipper开始自动切换。
mFlipper.startFlipping();
当点击时Spinner内的选项时,更改进入和退出的动画效果。
public void onItemSelected(AdapterView parent, View v, int position, long id) { switch (position) { case 0: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_up_out)); break; case 1: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out)); break; case 2: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this.R.anim.fade_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out)); break; default: mFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.hyperspace_in)); mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.hyperspace_out)); break; } }
这里的Animation都是自定义的动画效果,可以在res/anim内找到对应的XML文件,下面用push_up_in.xml来说明定义的大概用法。
因为这个动画是由几个动画复合组成的,所以外围就用一个set标签括起来,组成一个AnimationSet。
translate标签内主要定义位置的变化情况,fromYDelta="100%p",是指从ViewFlipper的正下方刚好一个View的高度的距离的地方开始出现,100%p是一个相对值,大于0为下方,小于0为上方。toYDelta="0",是指刚好达到布局文件的原始位置停止。android:duration="300",是指整个动作的时间用时为300毫秒,系统会根据这个时间自动调整速度。
alpha标签内定义的是透明度,0为全透明,1.0为不透明,过程为300毫秒,让View为逐渐出现的过程
<set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="300"/> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" /> </set>
push_up_out.xml,和push_left的两个标签都几乎一样的,应该很好理解。
hyperspace_in.xml更简单,只有一个alpha,所以外层没有set标签。startOffset是设置延迟。
hyperspace_out.xml相对复杂一点,set里面还包括有set,但仍然是由几个小动作一起组成的,可以一点点拆成来理解。
最外层是一个set,里面嵌套一个scale和一个set。
第一个scale标签可以理解为,以当前View的正中间位置为轴点,在700毫秒时间内,以加速放大的方式,将View的横长变为1.4倍,高度变为0.6倍。至于fillAfter这个标签我一直搞不懂这个功能,照SDK里的解释,是在连续动画中让View保持在动画的最后一帧,但照我的实验似乎没有什么效果,这个求高手指教。(查网上一些资料是说必须在代码里设置,这个是不是属于Android的Bug?)一个animationSet可以做为另一个animationSet的子集,这个很容易理解。rotate标签内的照字面意思应该很容易理解了,不再赘述了。
<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:fromXScale="1.0" android:toXScale="1.4" android:fromYScale="1.0" android:toYScale="0.6" android:pivotX="50%" android:pivotY="50%" android:fillAfter="false" android:duration="700" /> <set android:interpolator="@android:anim/accelerate_interpolator" android:startOffset="700"> <scale android:fromXScale="1.4" android:toXScale="0.0" android:fromYScale="0.6" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:duration="400" /> <rotate android:fromDegrees="0" android:toDegrees="-45" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:duration="400" /> </set> </set>
很多动画其实都是通过alpha, scale, rotate, translate这几个基本动作组成的。这些都属于Tween Animation。另外还有一种Frame Animation,类似放电影的效果,一帧帧播放动画,以后再说。
所有在XML内的设置的属性都可以在JAVA里找到对应的API函数,在Android SDK文档里可以查得到。
其实我觉得我这样写得都有点啰嗦了,Android的API的名字定义都很规范,从名字都已经可以判断出这个函数的功能了。
3D Transition的主要定义在animation包内,里面只有两个Java文件。
3D翻转其实并不是很复杂,最主要的是一个函数rotation.setAnimationListener(new DisplayNextView(position));在Transition3d的第99行。这个函数的主要作用是通过一个Listener,设置动画开始前、结束后,和重复动作时要触发的事件。
3D翻转效果主要由两个rotato动作构成,第二个动作在第一个动作完成后,由Listener来启动。这两个Animation连起来,看的时候就像3D旋转的效果了。
同时,在Rotate3dAnimation.java中,重新定义了一个Animation,覆写了initialize和applyTransformation方法。initialize是初始化动作,applyTransformation就定义动画效果的,这个是最主要的部分,传进来的是当前时间为总时间的百分比和动作,这里利用了转换矩阵。发现我的线性代数都忘了T_T,以后要重新看一遍。主要这个Camara不太理解,注释里也没写有这个类有什么用,从代码里猜测这个是保存当前的界面。
这样说来是简单,但做起来难啊。。