详解Android动画之Tween Animation

来源:互联网 发布:unity3d美工 编辑:程序博客网 时间:2024/06/05 14:24

前面讲了动画中的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);

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

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

Interpolator对象资源ID功能作用AccelerateDecelerateInterpolator@android:anim/accelerate_decelerate_interpolator先加速再减速AccelerateInterpolator@android:anim/accelerate_interpolator加速AnticipateInterpolator@android:anim/anticipate_interpolator先回退一小步然后加速前进AnticipateOvershootInterpolator@android:anim/anticipate_overshoot_interpolator在上一个基础上超出终点一小步再回到终点BounceInterpolator@android:anim/bounce_interpolator最后阶段弹球效果CycleInterpolator@android:anim/cycle_interpolator周期运动DecelerateInterpolator@android:anim/decelerate_interpolator减速LinearInterpolator@android:anim/linear_interpolator匀速OvershootInterpolator@android:anim/overshoot_interpolator快速到达终点并超出一小步最后回到终点

然后我们可以这样使用一个插值器:

<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">  <ImageViewandroid:id="@+id/piechart"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:src="@drawable/piechart"/>  <Buttonandroid:id="@+id/positive"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="顺时针"android:onClick="positive"/>  <Buttonandroid: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"><rotateandroid: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;@Overridepublic 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"><alphaandroid: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;@Overrideprotected 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);}@Overridepublic void onAnimationStart(Animation animation) {Log.i("alpha", "onAnimationStart called.");}@Overridepublic void onAnimationEnd(Animation animation) {Log.i("alpha", "onAnimationEnd called");}@Overridepublic 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"><translateandroid: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;@Overrideprotected 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"><scaleandroid: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"/><alphaandroid: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;@Overrideprotected 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);}}
几种动画运行效果如下图所示:



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 晒了太阳脸发红怎么办 新棉被没太阳晒怎么办 白掌的叶子发黄怎么办 栀子花长得太高怎么办 新羊毛被有味道怎么办 新买的衣服掉毛怎么办 羊毛被用水洗了怎么办 羊毛被一股骚味怎么办 水管被水垢堵了怎么办 花洒喷头堵了怎么办 花洒分水器堵了怎么办 冲马桶水溅出来怎么办 吃了不熟的芋头怎么办 吃多了肚子胀气怎么办 吃多了胃胀气怎么办 红薯吃多了胀气怎么办 裙子贴在腿上怎么办 薄裤子静电吸腿怎么办 雪纺衬衫起静电怎么办 吃烤饼不松软是怎么办 1岁宝宝睡眠不好怎么办 3岁幼儿睡眠不好怎么办 2岁幼儿睡眠不好怎么办 2岁宝宝睡眠不好怎么办 9岁儿童睡眠不好怎么办 3岁宝宝老踢被子怎么办 4岁宝宝老踢被子怎么办 四线锁边机跳线怎么办 引流管伤口洞红怎么办 甘蔗卡在喉咙里怎么办 棉花被子生虫了怎么办 绗缝羽绒服钻毛怎么办 宝珠笔没墨水了怎么办 衣服上画的笔印怎么办 黑笔芯弄衣服上怎么办 圆珠笔油在皮上怎么办 不小心吞了水银怎么办 小孩吃了洗发露怎么办? 脸上被铅笔戳了怎么办 小孩吃了铅笔芯怎么办 小孩把橡皮吃了怎么办