求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
详解Android动画之Tween Animation
 
作者 xiaochao1234的博客,火龙果软件    发布于 2014-04-18
 

前面讲了动画中的Frame动画,今天就来详细讲解一下Tween动画的使用。同样,在开始实例演示之前,先引用官方文档中的一段话:Tween动画是操作某个控件让其展现出旋转、渐变、移动、缩放的这么一种转换过程,我们成为补间动画。我们可以以XML形式定义动画,也可以编码实现。如果以XML形式定义一个动画,我们按照动画的定义语法完成XML,并放置于/res/anim目录下,文件名可以作为资源ID被引用;如果由编码实现,我们需要使用到Animation对象。如果用定义XML方式实现动画,我们需要熟悉一下动画XML语法:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"] >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromX="float"
android:toX="float"
android:fromY="float"
android:toY="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>

XML文件中必须有一个根元素,可以是<alpha>、<scale>、<translate>、<rotate>中的任意一个,也可以是<set>来管理一个由前面几个元素组成的动画集合。

<set>是一个动画容器,管理多个动画的群组,与之相对应的Java对象是AnimationSet。它有两个属性,android:interpolator代表一个插值器资源,可以引用系统自带插值器资源,也可以用自定义插值器资源,默认值是匀速插值器;稍后我 会对插值器做出详细讲解。android:shareInterpolator代表<set>里面的多个动画是否要共享插值器,默认值为 true,即共享插值器,如果设置为false,那么<set>的插值器就不再起作用,我们要在每个动画中加入插值器。

<alpha>是渐变动画,可以实现fadeIn和fadeOut的效果,与之对应的Java对象是AlphaAnimation。 android:fromAlpha属性代表起始alpha值,浮点值,范围在0.0和1.0之间,分别代表透明和完全不透 明,android:toAlpha属性代表结尾alpha值,浮点值,范围也在0.0和1.0之间。

<scale>是缩放动画,可以实现动态调控件尺寸的效果,与之对应的Java对象是ScaleAnimation。 android:fromXScale属性代表起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0 代表放大一倍;android:toXScale属性代表结尾的X方向上相对自身的缩放比例,浮点值;android:fromYScale属性代表起始 的Y方向上相对自身的缩放比例,浮点值;android:toYScale属性代表结尾的Y方向上相对自身的缩放比例,浮点 值;android:pivotX属性代表缩放的中轴点X坐标,浮点值,android:pivotY属性代表缩放的中轴点Y坐标,浮点值,对于这两个属 性,如果我们想表示中轴点为图像的中心,我们可以把两个属性值定义成0.5或者50%。

<translate>是位移动画,代表一个水平、垂直的位移。与之对应的Java对象是TranslateAnimation。

android:fromXDelta属性代表起始X方向的位置,android:toXDelta代表结尾X方向上的位 置,android:fromYScale属性代表起始Y方向上的位置,android:toYDelta属性代表结尾Y方向上的位置,以上四个属性都支 持三种表示方式:浮点数、num%、num%p;如果以浮点数字表示,代表相对自身原始位置的像素值;如果以num%表示,代表相对于自己的百分比,比如 toXDelta定义为100%就表示在X方向上移动自己的1倍距离;如果以num%p表示,代表相对于父类组件的百分比。

<rotate>是旋转动画,与之对应的Java对象是RotateAnimation。android:fromDegrees属性 代表起始角度,浮点值,单位:度;android:toDegrees属性代表结尾角度,浮点值,单位:度;android:pivotX属性代表旋转中 心的X坐标值,android:pivotY属性代表旋转中心的Y坐标值,这两个属性也有三种表示方式,数字方式代表相对于自身左边缘的像素值,num% 方式代表相对于自身左边缘或顶边缘的百分比,num%p方式代表相对于父容器的左边缘或顶边缘的百分比。

另外,在动画中,如果我们添加了android:fillAfter="true"后,这个动画执行完之后保持最后的状态;android:duration="integer"代表动画持续的时间,单位为毫秒。

如果要把定义在XML中的动画应用在一个ImageView上,代码是这样的:

ImageView image = (ImageView) findViewById(R.id.image);
Animation testAnim = AnimationUtils.loadAnimation(this, R.anim.test);
image.startAnimation(testAnim);

下面重点介绍一下插值器的概念:

首先要了解为什么需要插值器,因为在补间动画中,我们一般只定义关键帧(首帧或尾帧),然后由系统自动生成中间帧,生成中间帧的这个过程可以成为“插值”。插值器定义了动画变化的速率,提供不同的函数定义变化值相对于时间的变化规则,可以定义各种各样的非线性变化函数,比如加速、减速等。下面是几种常见的插值器:

<set android:interpolator="@android:anim/accelerate_interpolator">
...
</set>

<alpha android:interpolator="@android:anim/accelerate_interpolator"
.../>

如果只简单地引用这些插值器还不能满足需要的话,我们要考虑一下个性化插值器。我们可以创建一个插值器资源修改插值器的属性,比如修改AnticipateInterpolator的加速速率,调整CycleInterpolator的循环次数等。为了完成这种需求,我们需要创建XML资源文件,然后将其放于/res/anim下,然后再动画元素中引用即可。我们先来看一下几种常见的插值器可调整的属性:

<accelerateDecelerateInterpolator> 无

<accelerateInterpolator> android:factor 浮点值,加速速率,默认为1

<anticipateInterploator> android:tension 浮点值,起始点后退的张力、拉力数,默认为2

<anticipateOvershootInterpolator> android:tension 同上 android:extraTension 浮点值,拉力的倍数,默认为1.5(2 * 1.5)

<bounceInterpolator> 无

<cycleInterplolator> android:cycles 整数值,循环的个数,默认为1

<decelerateInterpolator> android:factor 浮点值,减速的速率,默认为1

<linearInterpolator> 无

<overshootInterpolator> 浮点值,超出终点后的张力、拉力,默认为2

下面我们就拿最后一个插值器来举例:

<?xml version="1.0" encoding="utf-8"?>
<overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:tension="7.0"/>

上面的代码中,我们把张力改为7.0,然后将此文件命名为my_overshoot_interpolator.xml,放置于/res/anim下,我们就可以引用到自定义的插值器了:

<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/my_overshoot_interpolator"
.../>

如果以上这些简单的定义还不能满足我们的需求,那么我们就需要考虑一下自己定义插值器类了。

我们可以实现Interpolator接口,因为上面所有的Interpolator都实现了Interpolator接口,这个接口定义了一个方法:float getInterpolation(float input);

此方法由系统调用,input代表动画的时间,在0和1之间,也就是开始和结束之间。

线性(匀速)插值器定义如下:

    public float getInterpolation(float input) {
return input;
}

加速减速插值器定义如下:

    public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

有兴趣的话,大家可以尝试一下自定义一个插值器。

讲了这么久的概念,下面我们就结合实例来演示一下几种Tween动画的应用。

先来介绍一下旋转动画的使用,布局文件/res/layout/rotate.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">
<ImageView
android:id="@+id/piechart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/piechart"/>
<Button
android:id="@+id/positive"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="顺时针"
android:onClick="positive"/>
<Button
android:id="@+id/negative"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="逆时针"
android:onClick="negative"/>
</LinearLayout>

我们定义了一个ImageView,用于显示一个饼状图,演示旋转动画,然后定义了两个按钮,用以运行编码实现的动画。动画定义文件/res/anim/rotate.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<rotate
android:fromDegrees="0"
android:toDegrees="+360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="5000"/>
</set>

最后再来看一下RotateActivity.java代码:

package com.scott.anim;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
public class RotateActivity extends Activity {
private int currAngle;
private View piechart;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rotate);
piechart = findViewById(R.id.piechart);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate);
piechart.startAnimation(animation);
}

public void positive(View v) {
Animation anim = new RotateAnimation(currAngle, currAngle + 180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
/** 匀速插值器 */
LinearInterpolator lir = new LinearInterpolator();
anim.setInterpolator(lir);
anim.setDuration(1000);
/** 动画完成后不恢复原状 */
anim.setFillAfter(true);
currAngle += 180;
if (currAngle > 360) {
currAngle = currAngle - 360;
}
piechart.startAnimation(anim);
}

public void negative(View v) {
Animation anim = new RotateAnimation(currAngle, currAngle - 180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
/** 匀速插值器 */
LinearInterpolator lir = new LinearInterpolator();
anim.setInterpolator(lir);
anim.setDuration(1000);
/** 动画完成后不恢复原状 */
anim.setFillAfter(true);
currAngle -= 180;
if (currAngle < -360) {
currAngle = currAngle + 360;
}
piechart.startAnimation(anim);
}
}

然后,看一下渐变动画,布局文件/res/layout/alpha.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">
<ImageView
android:id="@+id/splash"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:src="@drawable/splash"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="alpha"
android:onClick="alpha"/>
</FrameLayout>

动画定义文件/res/anim/alpha.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="3000"/>
</set>

AlphaActivity.java代码如下:

package com.scott.anim;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
public class AlphaActivity extends Activity implements AnimationListener {

private ImageView splash;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alpha);

splash = (ImageView) findViewById(R.id.splash);
Animation anim = AnimationUtils.loadAnimation(this, R.anim.alpha);
anim.setAnimationListener(this);
splash.startAnimation(anim);
}

public void alpha(View view) {
Animation anim = new AlphaAnimation(1.0f, 0.0f);
anim.setDuration(3000);
anim.setFillAfter(true);
splash.startAnimation(anim);
}
@Override
public void onAnimationStart(Animation animation) {
Log.i("alpha", "onAnimationStart called.");
}
@Override
public void onAnimationEnd(Animation animation) {
Log.i("alpha", "onAnimationEnd called");
}
@Override
public void onAnimationRepeat(Animation animation) {
Log.i("alpha", "onAnimationRepeat called");
}
}

接着看一下位移动画,布局文件/res/layout/translate.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/trans_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="@drawable/person"/>
<Button
android:id="@+id/trans_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="translate"
android:onClick="translate"/>
</FrameLayout>

动画定义文件/res/anim/translate.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/bounce_interpolator">
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="200"
android:toYDelta="300"
android:duration="2000"/>
</set>

然后TranslateActivity.java代码如下:

package com.scott.anim;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
public class TranslateActivity extends Activity {

private ImageView trans_iamge;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tanslate);
trans_iamge = (ImageView) findViewById(R.id.trans_image);
Animation anim = AnimationUtils.loadAnimation(this, R.anim.translate);
anim.setFillAfter(true);
trans_iamge.startAnimation(anim);
}

public void translate(View view) {
Animation anim = new TranslateAnimation(200, 0, 300, 0);
anim.setDuration(2000);
anim.setFillAfter(true);
OvershootInterpolator overshoot = new OvershootInterpolator();
anim.setInterpolator(overshoot);
trans_iamge.startAnimation(anim);
}
}

最后,我们再来看以下缩放动画,布局文件/res/layout/scale.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="@+id/scale_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:src="@drawable/person"/>
<Button
android:id="@+id/scale_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="scale"
android:onClick="sclae"/>
</LinearLayout>

动画定义文件/res/anim/scale.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/bounce_interpolator">
<scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="2.0"
android:pivotX="0.5"
android:pivotY="50%"
android:duration="2000"/>
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="3000"/>
</set>

然后ScaleActivity.java代码如下:

package com.scott.anim;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.BounceInterpolator;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
public class ScaleActivity extends Activity {

private ImageView scale_iamge;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scale);
scale_iamge = (ImageView) findViewById(R.id.scale_image);
Animation anim = AnimationUtils.loadAnimation(this, R.anim.scale);
anim.setFillAfter(true);
scale_iamge.startAnimation(anim);
}

public void sclae(View view) {
Animation anim = new ScaleAnimation(2.0f, 1.0f, 2.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(2000);
anim.setFillAfter(true);
BounceInterpolator bounce = new BounceInterpolator();
anim.setInterpolator(bounce);
scale_iamge.startAnimation(anim);
}
}

几种动画运行效果如下图所示:

 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
 
分享到
 
 


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...