学习内容
Ø 帧动画
Ø 补间动画
Ø 动画方式切换组件
能力目标
Ø 掌握Android中动画的基本概念及分类
Ø 熟练掌握帧动画的实现
Ø 熟练掌握各种补间动画的实现
Ø 掌握如何使用动画方式实现组件之间的切换效果
本章简介
在Android程序设计过程中,除了使用简单的按钮、文本框等简单控件来构建基本界面,我们还可以通过为界面添加动画效果,使得界面更加变得更加绚丽,更加吸引人。Android平台也提供了一套完整的动画框架,使得开发者可以用它开发出各种动画效果。
本章主要介绍Android系统中的动画:帧动画和补间动画。其中帧动画使用AnimationDrawable来实现,在本质上是将多个图像以相同或不同的时间间隔进行切换来实现动画。补间动画需要指定动画开始和结束状态,然后由系统自动生成中间状态的图像,它包括移动、缩放、旋转、透明度的变化等。除此之外我们还将学习Android默认提供的accelerate_interpolator、decelerate_interpolator、accelerate_decelerate_interpolator等多种动画渲染器。
2.1 Android中的动画
Android中的Animations动画效果多种多样,其中包括旋转、缩放、淡入淡出等,这些效果可以应用于绝大多数的控件(图片、按钮、文本)。总的来说,默认Android系统主要提供以下两类动画:
Ø 帧动画(Frame-By-Frame Animations):通过顺序播放事先做好的图像来实现动画效果,和电影相似。
Ø 补间动画(Tweened Animations):通过对场景里的对象不断进行图像变换(平移、缩放、旋转)来产生动画效果。具体来讲,Tween动画是通过预先定义一组指令(这组指令指定了图形变换类型、触发时间、持续时间等),程序沿着时间轴执行这些指令来实现动画效果。
2.2 帧动画
在Android系统中大多数免费应用都会在界面中添加广告以取得收入,而多数广告都如我们经常看到的GIF图片那样,几张不同的图片不断变换以增加广告内容的充实度,而这里就需要我们使用帧动画技术来实现这些效果。
帧动画实际上是由若干个以一定的时间间隔进行切换的图像组成的。比如电影的原理就类似于帧动画,一般电影是每秒25帧。即,电影在每秒钟之内会以相等的时间间隔连续播放25幅静态画面,由于人的视觉暂留,在这样的播放频率下,看起来这些画面好像是连续的。在第一章中我们在onDraw()方法中使用invalidate()方法不断地刷新View的方式实现的旋转动画,这种情况下,是不断地画出动画中的每一帧图像,它其实也相当于帧动画。
要在Android中实现帧动画,首先需要在res/anim目录下创建一个后缀为.xml的动画文件。然后在这个文件中指定动画中的静态图像和每一张静态图像的停留时间,这个时间的单位是毫秒。为了让用户看起来舒服,一般可以将所有的图像停留时间设为同一个值。动画文件的一般形式如下。
<animation-list android:oneshot="false"
xmlns:android="http:///apk/res/android">
<item android:duration="500" android:drawable="@drawable/a1"/>
<item android:duration="500" android:drawable="@drawable/a2"/>
……
</animation-list>
一般情况下,动画文件由一个<animation-list>标签和若干个<item>标签组成。其中<animation-list>标签的android:oneshot属性取值为true时表示动画只运行一遍,为false时动画会循环播放,这个属性是可选的,默认值是false。<item>标签的android:drawable属性 用来指定动画中静态图像资源的ID,android:duration用来指定每个图像的停留时间,这两个属性都是必选的,缺一不可。
编写完动画文件之后,就需要装载动画文件,并创建AnimationDrawable对象。AnimationDrawable是Drawable的子类,它在Drawable的基础之上提供了控制动画的功能。
实现帧动画的基本步骤是:
(1) 在drawable中插入一系列的图片,注意这里面图片的命名最好要有规律可循,以方便编程使用,例如我这里面的命名是a1、a2……。
(2) 在res/anim文件夹当中创建一个xml类型的文件,将所有帧都列出来以定义Animations动画序列,在此处可以通过oneshot设置动画是否重复播放。
示例2.1:
实现GIF动画的播放效果。
在屏幕上提供一个ImageView和四个Button,当用户单击这些Button按钮时,依次实现“开始动画”、“停止动画”、“运行一次动画”、“代码中添加动画”的功能。其中ImageView组件的作用是按照我们在动画文件中设置的顺序显示res/drawable目录下的静态图片。整个程序运行的效果和GIF图像基本一样。整下程序的运行效果如下图2.1.1和图2.1.2所示:
(1)编写动画文件代码如下:
<animation-list android:oneshot="false"
xmlns:android="http:///apk/res/android">
<item android:duration="500" android:drawable="@drawable/a1"/>
<item android:duration="500" android:drawable="@drawable/a2"/>
<item android:duration="500" android:drawable="@drawable/a3"/>
<item android:duration="500" android:drawable="@drawable/a4"/>
<item android:duration="500" android:drawable="@drawable/a5"/>
<item android:duration="500" android:drawable="@drawable/a6"/>
<item android:duration="500" android:drawable="@drawable/a7"/>
<item android:duration="500" android:drawable="@drawable/a8"/>
</animation-list>
(2)编写程序布局文件,在布局文件中只是提供一个id为imageViewId的ImageView组件和四个id分别为btn1、btn2、btn3、btn4的Button组件。
(3)编写Activity类,实现功能代码如下:
public class FrameByFrameActivity extends Activity {
private ImageView imageView =null;
private AnimationDrawable drawable = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.framebyframe);
imageView = (ImageView) findViewById(R.id.imageViewId);
//开始动画
Button btn = (Button) findViewById(R.id.btn1);
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//装载动画布局文件
imageView.setBackgroundResource(R.anim.framebyframe);
//构建动画
AnimationDrawable drawable = null;
drawable=(AnimationDrawable) imageView.getBackground();
//开始播放动画
drawable.start();
}
});
//停止动画
Button btn2 = (Button) findViewById(R.id.btn2);
btn2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
drawable.stop();
}
});
//运行一次动画
Button btn3 = (Button) findViewById(R.id.btn3);
btn3.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
drawable.setOneShot(true);
drawable.start();
}
});
//添加动画
Button btn4 = (Button) findViewById(R.id.btn4);
btn4.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//装载动画布局文件
//AnimationDrawable对象用来表示Frame动画
AnimationDrawable frameDrable = new AnimationDrawable();
Drawable drawable = null;
//装载资源
for(int i = 1 ; i <10 ;i++){
int id = getResources().getIdentifier("a"+i, "drawable", getPackageName());
drawable = getResources().getDrawable(id);
frameDrable.addFrame(drawable, 1000);//把每一帧要显示的内容添加进去
}
//设置动画不重复播放
frameDrable.setOneShot(false);
imageView.setBackgroundDrawable(frameDrable);
//开始播放动画
frameDrable.start();
}
});
}
}
在btn1按钮的单击事件中,我们实现了动画文件的装载、AnimationDrawable的构建及动画的播放功能。
除了示例代码中使用ImageView的setBackgroundResource()方法来装载动画文件,并通过ImageView的getBackground()方法获得AnimationDrawable对象实现动画效果之外,我们还可以使用getDrawable()方法来装载动画文件,代码如下:
AnimationDrawable drawable =
(AnimationDrawable) getResources().getDrawable(R.anim.framebyframe);
imageView.setBackgroundDrawable(drawable);
在btn4按钮的单击事件中,我们先通过new关键字声明了一个AnimationDrawable对象,然后利用Java代码通过循环的方式为这个对象添加了一系列的静态图片。最后调用start()方法让其运动起来。
通过上述代码我们会发现,所有对帧动画的控制都是通过AnimationDrawable实现的。本示例程序中用到的AnimationDrawable中与帧动画有关的方法如下:
Ø start():开始播放动画
Ø stop():停止播放动画
Ø void setOneShot(boolean b):
设置是否只播放一遍帧动画。这个方法的参数与动画文件中的<animation-list>标签的android:oneshot属性值的含义相同。
Ø void addFrame(Drawable frame, int duration)
向AnimationDrawable对象中添加新的帧。其中参数frame是一个Drawable对象,表示要添加的帧,该参数可以是静态图像,也可以是另一个动画。参数duration表示帧动画的停留时间,如果新添加的帧是动画,那么这停留时间就是新添加的动画可以播放的时间,如果到了停止时间,不管新添加的动画是否播放完,都会切换到下一个静态图像或动画。
2.3 补间动画
通过上述的帧动画(Frame-By-Frame Animations)技术,我们可以方便的制作出如flash般的动画效果,只需要我们准备好每一帧动画所需要的画面,然后按照组织好的顺序使其顺序播放,即可达到动画片似的效果,但是,如果仅仅是一个物体的简单移动,放大缩小等功能,我们依然需要为其准备不同时刻的静态画面,按照电影一秒内播放25帧的速度,四秒时长的动画效果我们就需要为其准备多达100张静态图片,这样看来依然过于繁琐,而对于这种简单的移动、放大缩小、旋转等动画效果,安卓系统也为我们提供了更加方便的动画生成技术,我们称之为补间动画(Tweened Animations)。
补间动画(Tweened Animations)是指在制作动画过程中,开发者只用定义动画的开始、结束等等关键帧信息,中间的变化效果由系统自动生成,所以称之为补间动画。
对于图像的简单移动、旋转、缩放等,都可以通过补间动画来实现。然而,当图像过于复杂时,由于系统无法预料下一幅画面的样子,此时不宜采用补间动画,要实现动画效果只能采用帧动画的形式。
因为补间动画只需要提供两帧图像(第一帧和最后一帧),并指定动画的持续时间即可。所以补间动画最大的优点是节省硬盘空间。
Android中使用Animation类代表抽象的动画类,它包含以下几个子类:
Ø TranslateAnimation:位移变化的动画,创建该动画时只要指定动画开始时的位置(以X、Y坐标来表示)、结束时的位置(以X、Y坐标来表示),并指定动画持续的时间即可。
Ø RotateAnimation:旋转动画,创建该动画时只要指定动画开始时的旋转角度、结束时的旋转角度,并指定动画持续的时间即可。由于旋转时以不同点为中心时旋转效果并不相同,因此指定旋转动画时还要指定“旋转中心”的坐标。
Ø ScaleAnimation:缩放动画,创建该动画时要指定动画开始时的缩放比(以X、Y轴的缩放参数表示)、结束时动画的缩放比以X、Y轴的缩放参数表示),并指定动画持续的时间。由于旋转时以不同点为中心时缩放效果并不相同,因此指定缩放动画时还要指定“缩放中心”的坐标。
Ø AlphaAnimation:透明度改变动画,创建该动画时需要指定动画开始时的透明度、结束时的透明度和动画持续时间,其中透明度的变化范围是1~0。
在本节中我们将通过具体的案例深入学习Android系统默认提供的移动、缩放、旋转和透明四种补间动画效果。
2.3.1 移动补间动画
《水果忍者》也许很多同学都玩过,游戏中玩家需要用手指模拟武士刀将上抛起的各种水果切开,那么这种水果上下移动的动画效果如何实现呢?这里我们就可以使用移动补间动画来实现。
移动是最常见的动画效果,可以通过配置文件或Java代码文件来实现。
示例2.2
上下跳动的小球。
在手机屏幕上显示一下上下移动的小球,用来模拟物体的自由下落:当小球从上到下移动时呈现加速状态,从下到上移动时呈现减速状态。
补间动画文件放在res/anim目录中,在动画文件中通过<translate>标签设置移动的效果。本示例用到两个动画渲染器:accelerate_interpolator、decelerate_interpolator。首先定义具体动画的文件。
translatescaletop.xml定义从下到上移动,减速效果。
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http:///apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="0"
android:fromYDelta="250"
android:toYDelta="0"
android:duration="2200" />
translatebottom.xml定义从上到下移动,加速效果。
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http:///apk/res/android"
android:interpolator="@android:anim/ decelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="250"
android:duration="2200" />
<translate>标签中设置了几个属性,这些属性的含义如下:
Ø android:interpolator:表示动画渲染器, Android系统一共为我们提供了linear_interpolator、accelerate_interpolator(动画加速器)、decelerate_interpolator(动画减速器)和accelerate_decelerate_interpolator(动画加速减速器)四种动画渲染器,其中动画加速减速器使动画在开始和结束时速度很慢,但在前半部分开始加速,后半部分开始减速。
Ø android:fromXDelta:动画起始位置的横坐标。
Ø android:toXDelta:动画结束位置的横坐标。
Ø android:fromYDelta:动画起始位置的纵坐标。
Ø android:toYDelta:动画结束位置的纵坐标。
Ø android:duration:动画持续的时间。
Activity类代码如下:
public class BallAnimationsActivity extends Activity implements AnimationListener {
private ImageView imageView = null;
private Animation animationBottom;//从上到下
private Animation animationTop;//从下到上
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ballanimations);
imageView = (ImageView) findViewById(R.id.imageview);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
imageView.startAnimation(animationBottom);
}
});
animationBottom = AnimationUtils.loadAnimation(this, R.anim.transloatebottom);
animationTop = AnimationUtils.loadAnimation(this, R.anim.transloatetop);
animationBottom.setAnimationListener(this);
animationTop.setAnimationListener(this);
}
@Override
public void onAnimationStart(Animation animation) {
//动画开始时调用
}
@Override
public void onAnimationEnd(Animation animation) {//动画结束时调用
//根据当前显示的动画决定下次显示哪一个动画
if (animation.hashCode() == animationBottom.hashCode())
imageView.startAnimation(animationTop);
else if (animation.hashCode() == animationTop.hashCode())
imageView.startAnimation(animationBottom);
}
@Override
public void onAnimationRepeat(Animation animation) {//动画循环时调用
}
}
代码解析:
其中ballanmimations.xml是一个只提供了一个包含id为imageView的ImageView组件和一个id为btn的Button组件的布局文件。
补间动画有动画开始、动画结束、动画循环3种状态:,我们可以通过android.view.animation.Animation.AnimationListener接口实现对这三种状态的监听。这个接口中定义的三个方法:onAnimationStart()、onAnimationEnd()、onAnimationRepeat()分别在动画开始、动画结束和动画循环时被调用。
将动画文件应用到指定的组件上,除了可以使用示例中调用startAnimation()方法外,还可以使用如下方法:
imageView.setAnimation(animationBottom);
animation.start();
程序中装载动画文件时用到了如下方法:
Animation AnimationUtils.loadAnimation(Context context, int id)
从资源文件中装载动画。其中id表示动画文件的资源ID。
单击【开始动画】按钮后,小球就会在垂直方向上按照我们的设置上下移动,效果如下图2.1.3所示。
2.3.2 缩放补间动画
在《愤怒的小鸟》的游戏中,当我们需要让小鸟由远及近或者由近及远飞翔时,那么它应该是出现一种由小变大或者由大变小的状态来模拟距离的改变,而这种动画的实现,我们就需要用到下面的缩放补间动画技术。
示例2.3:
实现一个可以跳动的心.跳动实际上就是不断地将心型的图像放大和缩小,因此本示例需要两个动画文件,一个表示放大后的状态,一个表示缩小后的状态。
心脏放大的配置文件scalelarge.xml代码如下:
<scale xmlns:android="http:///apk/res/android"
android:duration="500"
android:fromXScale="0.2"
android:toXScale="1.0"
android:fromYScale="0.2"
android:toYScale="1.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%" />
心脏缩小的配置文件scalesmall.xml代码如下:
<scale xmlns:android="http:///apk/res/android"
android:duration="500"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.2"
android:toYScale="0.2" />
<scale>标签中设置了几个属性,这些属性的含义如下:
Ø android:fromXScale:表示沿X轴缩放的起始比例。
Ø android:toXScale:表示沿X轴缩放的结束比例。
Ø android:fromYScale:表示沿Y轴缩放的起始比例。
Ø android:toYScale:表示沿Y轴缩放的结束比例。
Ø android:pivotX:表示沿X轴方向上缩放的中心点位置。
Ø android:pivotY:表示沿Y轴方向上缩放的中心点位置。
接下来在Activity中编写功能实现代码。
public class HeartScaleActivity extends Activity implements AnimationListener {
private Animation large;
private Animation small;
private ImageView imageView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.heartanimations);
imageView = (ImageView) findViewById(R.id.imageview);
large = AnimationUtils.loadAnimation(this, R.anim.scalelarge);
small = AnimationUtils.loadAnimation(this, R.anim.scalesmall);
large.setAnimationListener(this);
small.setAnimationListener(this);
imageView.startAnimation(small);
}
@Override
public void onAnimationEnd(Animation animation) {
if (animation.hashCode() == large.hashCode())
imageView.startAnimation(small);
else
imageView.startAnimation(large);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
}
}
其中heartanmimations.xml是一个只提供了一个包含id为imageView的ImageView布局文件。
任意选取两个时刻,程序运行效果如下图2.1.4和图2.1.5所示。
图2.1.4 心形放大的图像
图2.1.5 心型缩小图像
2.3.3 旋转补间动画
在游戏中,很多时候我们要实现某个物品按照某个点不断旋转的效果,例如《疯狂的小鸟》游戏中,当小鸟撞上障碍物时,就会不断旋转着跌落下去,这里小鸟的运动显然除了旋转,还有一个自由落体的运动过程,而单就旋转这种简单的动画来说,我们就可以运用Android系统中提供的旋转补间动画来实现。
示例2.4:模拟实现月球环绕地球旋转的效果,如下图2.1.6所示。
图2.1.6 地月系
定义地球自转动画的xml文件earth.xml内容如下:
<rotate xmlns:android="http:///apk/res/android"
android:duration="20000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toDegrees="360" />
定义月球围绕地球旋转动画的xml文件moon.xml内容如下:
<rotate xmlns:android="http:///apk/res/android"
android:duration="10000"
android:fromDegrees="0"
android:pivotX="200%"
android:pivotY="300%"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toDegrees="360" />
<rotate>标签中设置了几个属性,这些属性的含义如下:
Ø android: fromDegrees:表示旋转的起始角度。
Ø android:toDegrees:表示旋转的结束角度。
Ø android:repeatCount:用来设置旋转的次数。当取值为0时(默认),从0度旋转到360度,动画就会停止;如果属性值为N(N>0),动画会不停地显示N+1次;当取值为infinite或-1时,动画会永不停地运行下去。
Ø android:repeatMode:用来设置旋转的模式。默认值是restart,该属性值只有当android:repeatCount设置成大于0的数或infinite时才起作用。该属性取值reverse时表示偶数次显示动画时会做与动画文件定义的方向相反的动作。
Ø pivotX:旋转支点横坐标。
Ø pivotY:旋转支点纵坐标。
pivotX和pivotY的取值有两种:float或百分数,分别是相对于物体左(上)边距的像素表示或相对于物体左(上)边距的百分数表示。旋转支点坐标的具体计算公式如下:
假如物体原来的坐标是(x0,y0),采用像素形式时pivotX=x1,pivotY=y1,采用百分比形式时pivotX=n1%,pivotY=n2%。那么最终旋转中心的坐标为(x0+x1,y0+y1)或(x0+width*n1%,y0+height*n2%),其中width和height分别指图片的宽度和高度。
Activity类代码:
public class EarthMoonActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthmoon);
ImageView moon = (ImageView) findViewById(R.id.moon);
ImageView earth = (ImageView) findViewById(R.id.earth);
Animation moonAnimation = AnimationUtils.loadAnimation(this, R.anim.moon);
Animation earthAnimation = AnimationUtils.loadAnimation(this, R.anim.earth);
moon.startAnimation(moonAnimation);
earth.startAnimation(earthAnimation);
}
}
其中布局文件earthmoon.xml采用绝对布局,在其中放置了两个id分别为moon和earth的ImageView组件,详细代码如下:
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http:///apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="vertical" >
<ImageView
android:id="@+id/moon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_x="50dp"
android:layout_y="50dp"
android:src="@drawable/moon" />
<ImageView
android:id="@+id/earth"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_x="120dp"
android:layout_y="200dp"
android:src="@drawable/ball" />
</AbsoluteLayout>
运行程序,会发现代表月亮的图片会按照逆时针方向围绕着地球旋转,而地球本身也会按照顺时针的方向围绕着自身的地轴旋转。
2.3.4 透明补间动画
很多游戏在设计时,都会让已经被消灭的敌人慢慢地在屏幕中变成透明状,最后完全消失,以避免挤占宝贵的屏幕显示资源,而在Android系统中,这种效果同样十分简单,只需要运用我们下面提到的这种技术即可——透明补间动画。
示例2.5:
通过改变图片透明度实现屏幕上对象逐渐消失的效果。
动画效果定义文件alpha.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http:///apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:shareInterpolator = "true">
<alpha
android:fromAlpha="1.0"
android:toAlpha = "0.0"
android:startOffset= "200"
android:duration = "3000"
/>
</set>
这个文件定义中各个属性含义如下:
Ø android:fromAlpha:表示起始透明度,取值在0.0~1.0之间,其中0.0表示完全透明,1.0表示完全不透明。
Ø android:toAlpha:表示结束透明度。
Ø android:shareInterpolator = "true":设置内部所有的控件共享Interpolator。
Ø android:startOffset:开始时间偏移量,指在动画开始前等待的时间。
布局文件代码:
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http:///apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="vertical" >
<ImageView
android:id="@+id/earth"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_x="120dp"
android:layout_y="100dp"
android:src="@drawable/ball" />
</AbsoluteLayout>
Activity类代码:
public class EarthMoonActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.earthmoon);
ImageView earth = (ImageView) findViewById(R.id.earth);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha);
earth.startAnimation(animation);
}
}
某一时刻程序的运行效果如下图2.1.7所示:
图2.1.7 透明效果
2.4 动画方式切换各组件
最后让我们将上述提到的几种技术融合在一起,运用到我们的Android组件中,为Android系统组件的切换提供绚丽的动画效果。
凡是使用过Android手机的用户,都一定会被它里面的程序组件之间的切换效果所吸引,比如Android系统自带的看图软件在各图片之间切换时的过渡效果。本节课中我们就借助android.widget.ViewFliper类来模拟实现这种过渡效果。
示例2.6:
实现Android中查看图片时的过渡效果。
具体效果如下图2.1.8和2.1.9所示,第一种效果是移动切换,第二种效果是淡入淡出切换。
图2.1.8 水平移动切换
图2.1.9 淡入淡出切换
本示例程序使用布局文件layout1.xml、layout2.xml、layout3.xml定义了3个View,每一个View中都包含一个用来显示图像的ImageView组件。当用户触摸第一个图像时,会以水平向左移动的方式切换到第二个图像,触摸第二个图像时会以淡入淡出的方式切换到第三个图像(通过透明度补间动画实现)。
水平移动向左切入的动画文件translatein.xml的内容如下:
<translate xmlns:android="http:///apk/res/android"
android:duration="3000"
android:fromXDelta="320"
android:fromYDelta="0"
android:interpolator="@anim/linear_interpolator"
android:toXDelta="0"
android:toYDelta="0" />
水平移动向左切出的动画文件translateout.xml内容如下:
<translate xmlns:android="http:///apk/res/android"
android:duration="3000"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@anim/linear_interpolator"
android:toXDelta="-320"
android:toYDelta="0" />
淡入淡出动画的淡入效果文件alphain.xml的内容如下:
<alpha xmlns:android="http:///apk/res/android"
android:duration="2000"
android:fromAlpha="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="1" />
淡入淡出动画的淡出效果文件alphaout.xml的内容如下:
<alpha xmlns:android="http:///apk/res/android"
android:duration="2000"
android:fromAlpha="1"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="0" />
Activity类代码如下:
public class ViewFlipperActivity extends Activity implements OnTouchListener {
private ViewFlipper viewFlipper;
private Animation translateIn;
private Animation translateOut;
private Animation alphaIn;
private Animation alphaOut;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (view.getId()) {
case R.id.imageview1://触摸第一个图像时:移动补间动画
viewFlipper.setInAnimation(translateIn);
viewFlipper.setOutAnimation(translateOut);
break;
case R.id.imageview2://触摸第二个图像时:透明渐变补间动画
viewFlipper.setInAnimation(alphaIn);
viewFlipper.setOutAnimation(alphaOut);
break;
}
viewFlipper.showNext();//显示下一个View
return false;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewFlipper = (ViewFlipper) getLayoutInflater().inflate(R.layout.viewflipper, null);
View view1 = getLayoutInflater().inflate(R.layout.layout1, null);
View view2 = getLayoutInflater().inflate(R.layout.layout2, null);
View view3 = getLayoutInflater().inflate(R.layout.layout3, null);
viewFlipper.addView(view1);
viewFlipper.addView(view2);
viewFlipper.addView(view3);
setContentView(viewFlipper);
translateIn = AnimationUtils.loadAnimation(this, R.anim.translatein);
translateOut = AnimationUtils.loadAnimation(this, R.anim.translateout);
alphaIn = AnimationUtils.loadAnimation(this, R.anim.alphain);
alphaOut = AnimationUtils.loadAnimation(this, R.anim.alphaout);
ImageView imageView1 = (ImageView) view1.findViewById(R.id.imageview1);
ImageView imageView2 = (ImageView) view2.findViewById(R.id.imageview2);
imageView1.setOnTouchListener(this);
imageView2.setOnTouchListener(this);
}
}
其中布局文件viewflipper.xml的代码如下:
<ViewFlipper xmlns:android="http:///apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ViewFlipper>
运行本程序,触摸第一幅图像会以水平移动的方式切换到第二幅图像,再次触摸第二幅图像会以淡入淡出的方式切换到第三幅图像。具体程序运行效果请参看图2.1.8和图2.1.9。
任务实训部分
1:利用帧动画技术开发一个游戏人物走动的小游戏
训练技能点
帧动画的实现原理及技巧
需求说明
在任何一款游戏中,都不可避免地出现人物等对象走动的情景,结合本章所学的知识,我们可以事先提供一系列的图片,然后利用帧动画的原理实现。
实现步骤
具体的实现步骤请参看课本2.2节中的内容。本案例的难点是准备合适的人物行走过程中的图像,然后在动画文件中进行合适的设置。
2: 模拟实现汽车由近到远逐渐消失的场景
训练技能点
Ø 移动补间动画
Ø 缩放补间动画
Ø 透明补间动画
需求说明
在我们的手机程序中会经常看到一个物体由远到近或由近到远、体积由大到小或由小到大、逐渐透明或逐渐消失的应用。比如极品飞车游戏中渐行渐远的汽车。
本实训中要求模拟实现汽车由近到远逐渐消失的过程。汽车由近到远可通过移动补间动画实现;在消失过程中体积变小的过程可以通过缩放补间动画实现;为了增加用户的观感,可以在汽车消失的过程中为汽车设置一个透明度逐渐变化的过程,这个可通过透明补间动画实现。
巩固练习
一、简答题
1. 简述实现帧动画的基本步骤。
2. 简要描述Android默认提供的四类补间动画。
二、上机练习
完成一个蝴蝶振动翅膀飞动的效果,蝴蝶的振翅效果可通过逐帧动画实现,飞行时位置的改变可通过补间动画实现。