【前言】对于一款应用而言,除了程序健壮之外,就是用户体验要好了。用户体验是更为直观的展现和吸引用户的手段,一方面是要符合用户的操作习惯,另外就是要有让人愉悦的界面。纵观市面上的应用,无不是在这几方面下功夫。使用动画是让应用变得更绚丽的重要手段,当然,是适度合理的使用动画。从早前的Android版本开始,系统就提供了两种动画,补间动画(Tween)和帧动画(Frame),Android3.0后又提供了属性动画(Property)。结合canvas和camera的使用,我们就可以实现各种各样的动画效果了(甚至伪3D效果)。
先说说补间动画,补间动画和帧动画都是应用于View及其子类(widget)的动画,其原理是在View绘制过程中应用各种变化效果(平移/缩放/旋转/渐变),View本身在播放动画过程中和结束后其属性并没有改变,你可以理解为“障眼法”,至于更为详细的动画播放原理,大家可以多了解了解源码中View的绘制机制,这里不解释了。
补间动画有两种实现方法,硬编码和读取XML文件。
硬编码就是在编码中使用Anamation抽象类的几个具体实现类TranslateAnimation,RotateAnimation,AlphaAnimation,ScaleAnimation。从类名就可以看出,这几个实现类分别对应了补间动画的4个效果,当然,更多时候我们需要结合这几种动同时播放的时候,就要用到AnimationSet这个类。
因为这几种都是继承于Animation这个基类,所以我们先了解下Animation的几个重要属性:
1.duration 动画持续时间,由于补间动画本质上来说是一种变化效果,所以持续时间就是这种变化效果的时间,在编码中,我们通过setDuration()来设置;
2.interpolator 动画速率变换器 结合这个变换器动画可以做出各种不同的效果,比如先快后慢(默认)的播放,匀速播放,以及更为复杂的反弹播放等;
@android:anim/accelerate_interpolator: 越来越快
@android:anim/decelerate_interpolator:越来越慢
@android:anim/accelerate_decelerate_interpolator:先快后慢
@android:anim/anticipate_interpolator: 先后退一小步然后向前加速
@android:anim/overshoot_interpolator:快速到达终点超出一小步然后回到终点
@android:anim/anticipate_overshoot_interpolator:到达终点超出一小步然后回到终点
@android:anim/bounce_interpolator:到达终点产生弹球效果,弹几下回到终点
@android:anim/linear_interpolator:均匀速度。
3.stratOffset 播放时间偏移 这个属性在几个动画联合播放的时候更多用到,主要是播放的时间先后顺序。
而start,cancel方法则是对外的接口。
而作为实现类,TranslateAnimation等除了以上的几个基本参数外,还有各种播放动画需要的参数,比如平移动画的起始位置和结束位置,缩放动画的X,Y轴缩放位置等这些都是通过实现类的构造注入的;比如
RotateAnimation (float fromDegrees, float toDegrees)
TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
AlphaAnimation(float fromAlpha, float toAlpha)
ScaleAnimation (float fromX, float toX, float fromY, float toY)
在设置了这些动画的属性后,我们就可以应用于View上来播放动画效果了;看代码
img = (ImageView) findViewById(R.id.img);
Animation translate = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 100,
Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 100);
translate.setDuration(2000);
img.startAnimation(translate);
上面是平移动画的一个简单实现,有几个地方值得注意,首先我们说过补间动画是应用于View的,所以设置动画和播放动画的都是由View来完成的,其次构造函数的几个动画参数中,除了平移的初始坐标以及完成坐标外,还有几个参数是相对位置的类型(分为绝对位置类型,相对于自己位置和相对于父控件位置),如果不设置这几个类型的话,都是默认为相对于自己位置的。最后就是要设置动画的持续时间。
说道动画的位置我们有一点要明白,Android的原始锚点是在屏幕的左上角(即X,Y轴的0,0点),往下Y正,往右X正,反之亦然。所以在表示起始位置和结束位置的时候,我们除了可以用绝对的位置坐标之外,还可以用诸如100%,0%p,-100%p来表示:
再看看渐变动画,渐变动画只有起始alpha值和结束alpha值两个参数,0代表完全透明,1则是完全不透明。
img = (ImageView) findViewById(R.id.img);
animation = new AlphaAnimation(0, 1) ;
animation.setDuration(2000);
img.startAnimation(animation);
下面是缩放动画,缩放动画的参数里面,起始大小1代表本身View的大小,0代表不可见,2即代表了2倍于原始的大小
img = (ImageView) findViewById(R.id.img);
animation = new ScaleAnimation(1, 2, 1, 2, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0);
animation.setDuration(3000);
img.startAnimation(animation);
最后是旋转动画
img = (ImageView) findViewById(R.id.img);
animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 1.0f);
animation.setDuration(3000);
img.startAnimation(animation);
应用这四种动画并不难,重要的是理解每个参数的意义,特别注意一下伸缩模式和伸缩值的实际作用。
说完了硬编码方式实现补间动画,另外一种实现方式就是读取XML文件实现动画了,这个在平时项目中也用的较为频繁,我们在XML文件里定义好动画的属性和顺序,然后在编码中读取播放之。
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="50"
android:fromYDelta="0"
android:toYDelta="100"
android:duration="2000"
android:interpolator="@android:anim/accelerate_interpolator"/>
<rotate
android:fromDegrees="0"
android:toDegrees="90"
android:duration="2000"
android:startOffset="2000"/>
</set>
如上图所示,在XML文件里设置好一个动画集合,集合里可以包括我们上面提到的4种动画的任意一种或多种。
animation = AnimationUtils.loadAnimation(this, R.anim.myanim);
img.startAnimation(animation);
说道AnimationSet,我再补充一下硬编码中播放动画集合的实现,通过AnamationSet可以组合多种动画效果,达到和上面XML读取动画集合的效果:
AnimationSet set = new AnimationSet(false); // 设置平移动画的起始位置和结束位置
TranslateAnimation trans = new TranslateAnimation(0, 100, 0, 100); // 设置平移动画的持续时间
trans.setDuration(2000); // 将平移动画加入到集合
set.addAnimation(trans); // 设置旋转动画的起始角度和结束角度
RotateAnimation rotate = new RotateAnimation(0, 90); // 设置旋转动画的持续时间
rotate.setDuration(2000); // 设置旋转动画的播放延迟(设置成2000表示旋转动画在前面的平移动画结束后才开始播放)
rotate.setStartOffset(2000); // 把旋转动画加入集合
set.addAnimation(rotate); // 播放动画
img.startAnimation(set);