1.基本动画使用方式
在包com.example.android.apis.view下面的Animation1~3有各种使用方式,分别来进行介绍。
Animation1.java
如下所示(原始代码在包com.example.android.apis.view下面)
package
com.example.android.apis.view;
// Need the following import to
get access to the app resources, since this
// class is in a sub-package.
import
com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import
android.view.animation.Animation;
import
android.view.animation.AnimationUtils;
public class Animation1 extends
Activity implements View.OnClickListener {
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_1);
View loginButton =
findViewById(R.id.login);
loginButton.setOnClickListener(this);
}
public void onClick(View v) {
Animation shake =
AnimationUtils.loadAnimation(this, R.anim.shake);
findViewById(R.id.pw).startAnimation(shake);
}
R.layout.animation_1对应的XML文件为:
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dip"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"
android:text="@string/animation_1_instructions"
/>
<EditText
android:id="@+id/pw"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:singleLine="true"
android:password="true"
/>
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/googlelogin_login"
/>
</LinearLayout>
此XML文件为程序的主运行界面。如何实现动画呢?
实际上实现动画有两种方式,一种是在代码中构造Animation对象,一种是在XML文件中定义相关的资源。
如果构造对象,则应该分别新建AlphaAnimation等对象,而如果是XML文件中,则应该使用alpha等标签。在本例中,使用的是XML文件来创建Animation对象。
XML
中
alpha
渐变透明度动画效果
scale
渐变尺寸伸缩动画效果
translate
画面转换位置移动动画效果
rotate
画面转移旋转动画效果
|
JavaCode
中
AlphaAnimation
渐变透明度动画效果
ScaleAnimation
渐变尺寸伸缩动画效果
TranslateAnimation
画面转换位置移动动画效果
RotateAnimation
画面转移旋转动画效果
|
在OnCreate函数中,通过绑定Button实现对按钮事件的监听。
在onClick函数中,定义了点击按钮时候触发的动作,这里面的代码即实现相应的特效的代码。从代码中可以看到,这里首先执行下面的代码:
Animation shake =
AnimationUtils.loadAnimation(this, R.anim.shake);
findViewById(R.id.pw).startAnimation(shake);
在这段代码中,通过loadAnimation函数来载入动画元素,而动画资源则是在R.anim.shake中定义。找到该XML文件,内容如下:
<?xml version="1.0"
encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="10"
android:duration="1000"
android:interpolator="@anim/cycle_7"
/>
从中可以看到,该XML文件中,通过标签tranlate来定义平移的动作,并且设定了相关的参数,另外,注意其中的interpolator参数,该参数的设定是通过另外一个XML文件cycle_7来设定的。内容如下:
<?xml version="1.0"
encoding="utf-8"?>
<cycleInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"
android:cycles="7" />
至此,完成了动画的Animation,即参数的设定,最终就是调用AnimationUtils.loadAnimation来创建Animation对象shake,然后通过某个View的字函数startAnimation在该View上启动该动画。
比如这里:
findViewById(R.id.pw).startAnimation(shake);
首先获得的是password的那个EditText的View,然后在该View上调用startAnimation方法,启动shake这种动画。效果就是点击login登录按钮后,password的编辑框会出现来回抖动的效果。
既然弄清楚了Animation的两种使用方法,并且在上面中通过剖析Android的API
Demo了解了使用XML来实现动画效果的例子,那么下面我们自己动手,利用Java
Code的办法,实现同样的效果。
具体过程如下:
-
首先新建一个Android项目功能,然后编辑main.xml文件,添加一个Button和EditText控件,实现类似的原来那个例子那样的控件效果。
-
编辑OnCreate函数,在代码中实现前面的这些效果。
代码如下:
import android.app.Activity;
import
android.app.SearchManager.OnCancelListener;
import android.os.Bundle;
import android.view.View;
import
android.view.View.OnClickListener;
import
android.view.animation.Animation;
import
android.view.animation.AnimationUtils;
import
android.view.animation.CycleInterpolator;
import
android.view.animation.Interpolator;
import
android.view.animation.TranslateAnimation;
public class AnimationTest
extends Activity {
/** Called when the activity
is first created. */
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View login =
findViewById(R.id.login);
login.setOnClickListener(new
OnClickListener() {
@Override
public void
onClick(View v) {
TranslateAnimation
ta = new TranslateAnimation(0, 10, 0, 0);
ta.setDuration(1000);
ta.setInterpolator(new
CycleInterpolator(7));
findViewById(R.id.passwd).startAnimation(ta);
}
});
}
}
-
运行该工程后,就能够达到和Demo例子中同样的效果。
-
代码解读:
其实功能很简单,原始Demo是通过loadAnimation函数读取XML文件,那么我们只需要新建对应的Animation对象就行了。原始例子中使用的是Translate标签,对应的就是TranslateAnimation类,为此新建该对象,设定的参数就是原XML文件中的fromXDelta,toXDelta等等,由于原来的标签没有设定Y方向上的参数,所以使用默认的0,0.然后观察发现原始还是用了一个cycleInterpolator的XML资源,其中定义了一个cycle值,为此同样找到Java
Code对应的类,new一个这样的对象并设定参数。最终同样的对密码控件实现该特效效果,达到同样的效果。
2.利用XML来定义动画
在分析完上面这个最基本的动画特效使用之后,下面继续分析API
Demo中剩余的两个例子,它们分别是位于com.example.android.apis.view包下面的Animation2.java和Animation3.java文件。
首先分析Animation2.java对应的工程,原文件如下。
package
com.example.android.apis.view;
// Need the following import to
get access to the app resources, since this
// class is in a sub-package.
import
com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import
android.view.animation.AnimationUtils;
import
android.widget.AdapterView;
import
android.widget.ArrayAdapter;
import android.widget.Spinner;
import
android.widget.ViewFlipper;
public class Animation2 extends
Activity implements
AdapterView.OnItemSelectedListener
{
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_2);
mFlipper = ((ViewFlipper)
this.findViewById(R.id.flipper));
mFlipper.startFlipping();
Spinner s = (Spinner)
findViewById(R.id.spinner);
ArrayAdapter<String>
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,
mStrings);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(adapter);
s.setOnItemSelectedListener(this);
}
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,
android.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;
}
}
public void
onNothingSelected(AdapterView parent) {
}
private String[] mStrings = {
"Push up",
"Push left", "Cross fade", "Hyperspace"};
private ViewFlipper mFlipper;
}
从代码中可以看到,该类有一个ViewFlipper类型的成员变量,以及定义了菜单项的字符串数组。在OnCreate函数中,首先设定程序的主界面布局为animation_2.xml文件,该文件的内容如下:
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dip"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewFlipper
android:id="@+id/flipper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:flipInterval="2000"
android:layout_marginBottom="20dip"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_3"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="26sp"
android:text="@string/animation_2_text_4"/>
</ViewFlipper>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:text="@string/animation_2_instructions"
/>
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
从该XML文件中可以看到主界面的组成,一个ViewFlipper控件,一个显示提示信息的TextView,以及一个Spinner控件。所谓的ViewFlipper是一个多View的集合,但是每次都只能够显示出一个View,从最终的动画效果可以看到,该ViewFlipper中的每一个TextView,都以事先定义的某种动画形式不断的切换,轮流的显示出来。Spinner则是一个选择菜单,点击后出现下拉菜单,让用户选择某个选项,在这里,每一个选项的内容就是数组mStrings的内容。
图
2-1
Spinner
的效果
最终的效果就是,用户通过点击Spinner中的某个选项,可以选择不同的效果。而上方的那个ViewFlipper则以该种动画效果轮流显示出每一个TextView,ViewFlipper的四个子TextView得以轮流动画显示,消失。
在OnCreate函数中,首先获得ViewFlipper控件,然后通过调用startFlipping函数,开启一个计时器来循环显示出子View。此后,获得Spinner控件,然后利用mString数组创建一个ArrayAdapter,并指定为该Spinner的Adapter,最后,调用setOnItemSelectedListener开启一个监听选项的监听器,每当选择不同的选项时,进入不同的处理过程。
在分析完OnCreate函数后,整个工程就剩下选项被选中时候的函数实现了,即onItemSelected函数,当程序启动后OnCreate函数中添加了监视器,开始监听。用户一点点击选择了某个选项,就会根据这个position来进入不同的处理过程中。从代码中可以看到,switch……case的结构,分别针对用户选择
"Push
up", "Push left", "Cross fade", "Hyperspace"
这四个菜单时候的动作,在每个选项中的动作类似,因此只针对第一个进行介绍。
case 0:
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_in));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
R.anim.push_up_out));
break;
在用户选择了第一个Push
Up菜单后,该ViewFlipper通过使用setInAnimation函数来设定一个进入到屏幕中的View的动画(Specifies
the animation used to animate a View that enters the
screen.)通过使用setOutAnimation来指定一个离开屏幕时候的View的动画(Specifies
the animation used to
animate a View that exit the
screen.)这两个函数的参数都是一个Animation类型的对象,在前面第一部分的讲解中知道,有两种办法可以得到该对象。
-
XML
文件中定义,利用AnimationUtils.loadAnimation来载入该动画
-
利用Java
Code的Animation类来创建各种类型的对象。
在这里,使用的是第一种办法。查看相应的XML文件。
push_up_in.xml
文件
<?xml version="1.0"
encoding="utf-8"?>
<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>
从代码中可以看到,这是一个动画集合,包括一个translate,即平移动画,以及一个alpha,即透明度渐变的动画。在标签中分别设定了变化的参数,持续的时间等等。
从代码以及最终的运行效果可以知道,该动画特效就是,进入的时候从Y轴坐标100变化到0,即从下往上进入屏幕,透明度从0变为1,即从开始的不可见,逐渐变的清晰可见。类似的,push_up_out则实现相反的效果,在XML文件中有相应的表示。
同理,push_up_out.xml文件也可以采用类似的方法分析。
至此,我们分析完了第二个工程,对整个动画如何实现,如何正确的调用Animation函数都有了一个更清晰的认识。
3.利用JavaCode来实现动画
最后,我们简单来分析下第三个工程,因为上面两个工程的分析,最后一个的实现机制也是类似的。
Animation3.java
package
com.example.android.apis.view;
// Need the following import to
get access to the app resources, since this
// class is in a sub-package.
import
com.example.android.apis.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import
android.view.animation.AnimationUtils;
import
android.view.animation.Animation;
import
android.view.animation.TranslateAnimation;
import
android.widget.AdapterView;
import
android.widget.ArrayAdapter;
import android.widget.Spinner;
public class Animation3 extends
Activity implements AdapterView.OnItemSelectedListener {
private static final String[]
INTERPOLATORS = {
"Accelerate",
"Decelerate", "Accelerate/Decelerate",
"Anticipate",
"Overshoot", "Anticipate/Overshoot",
"Bounce"
};
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_3);
Spinner s = (Spinner)
findViewById(R.id.spinner);
ArrayAdapter<String>
adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item,
INTERPOLATORS);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(adapter);
s.setOnItemSelectedListener(this);
}
public void
onItemSelected(AdapterView parent, View v, int position, long id) {
final View target =
findViewById(R.id.target);
final View targetParent =
(View) target.getParent();
Animation a = new
TranslateAnimation(0.0f,
targetParent.getWidth()
- target.getWidth() - targetParent.getPaddingLeft() -
targetParent.getPaddingRight(),
0.0f, 0.0f);
a.setDuration(1000);
a.setStartOffset(300);
a.setRepeatMode(Animation.RESTART);
a.setRepeatCount(Animation.INFINITE);
switch (position) {
case 0:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.accelerate_interpolator));
break;
case 1:
a.setInterpolator(AnimationUtils.loadInterpolator(this,
android.R.anim.decelerate_interpolator));
break;
case 2:
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:
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.startAnimation(a);
}
public void
onNothingSelected(AdapterView parent) {
}
}
同工程2,在OnCreate函数中,设定了程序运行的主界面的layout,包括两个TextView和一个Spinner,Spinner同样是一个选择菜单,两个TextView中,一个是显示的标签,保持不变,另外一个实现动画特效的View。
Animation3.xml文件:
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="10dip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false">
<TextView
android:id="@+id/target"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="26sp"
android:text="@string/animation_3_text"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dip"
android:layout_marginBottom="5dip"
android:text="@string/animation_2_instructions"
/>
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
图3-1 Spinner选项
回到代码中,当用户选择某个选项时,进入到onItemSelected函数,此时获得带显示动画特效的那个TextView的引用以及它的父View,然后新建一个Animatioin,注意此处没有通过XML文件来定义,而是利用Java
Code来创建动画特效。通过设置各种参数,定义特效的实现形式。其中下面的代码需要注意:
Animation a = new
TranslateAnimation(0.0f,
targetParent.getWidth()-target.getWidth()-targetParent.getPaddingLeft()
-
targetParent.getPaddingRight(),0.0f,
0.0f);</LinearLayout>
为何要使用targetParent来计算长宽,而不是直接使用自己这个TextView呢?原因在于,该TextView是位于整个layout中的,而待实现的这个特效,实际上是要这个TextView在父layout上面左右移动(或者是其他运行形式),所以,运动的范围要局限在父对象中,因此是使用targetParent而不是target来设定该Animation。
余下的工作就是设定各种参数,对于本函数中的Swtich……case,则只是起到了修改Interpolator的作用,用户在选中不同的Interpolator后,该TextView将采用不同的形式来运动,那么,何为Interpolator对象呢?
SDK中的解释再清楚不过了:
"
An
interpolator defines the rate of change of an animation. This allows
the basic animation effects (alpha, scale, translate, rotate) to be
accelerated, decelerated, repeated, etc."
也就是说Interpolator是一个定义了动画变化的快慢速率的东西,它允许定义基本的动画效果为加速,减速或者重复显示等等效果。
最后,完成了上面的工作后,通过调用target.startAnimation(a);来使得target这个TextView按照设定的动画效果a进行变换显示。
最后做一个总结:实现动画的方式有两种:XML和JavaCode,还有,学习使用的最好办法是看Sample,查SDK文档,虽然初看Sample可能觉得有些困难,但是慢慢查文档,遇到复杂的用法和控件就先查查文档看看有没有,或者Google之,慢慢就会明白了。还有,学习之余多进行变化,比如换种方式实现,或者注释掉某行代码,再查看效果,即可对关键点有一个更清晰的了解。
posted on 2011-10-22 10:27
deercoder 阅读(4826)
评论(0) 编辑 收藏 引用 所属分类:
Android