Android几种动画的总结(逐帧动画、补间动画)

逐帧动画

逐帧动画也叫 Drawable Animation,是最简单最直观的动画效果。

在Android 中实现逐帧动画就是由设计师给出一系列状态不断变化的图片,开发者就指定这些图片显示的持续时间,然后顺序开始播放这些图片,就形成了动画了。

使用逐帧动画 既可以使用XML的方法实现,也可以使用代码来实现。

XML

首先把资源文件(每一帧的图片)放在 res/drawable 下。 如图:

然后在这里 新建一个XML文件。 在这个文件中使用的 <animation-list>标签来定义动画。使用<item>标签来定义动画的每一帧,并在每一个<item>中指定自己的属性,例如 持续时间 android:duration="300" 、 这一帧使用的图片 android:drawable="@drawable/z_1_die_01" 。

frme_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">

    <item
        android:drawable="@drawable/z_1_die_01"
        android:duration="300"/>
    <item
        android:drawable="@drawable/z_1_die_02"
        android:duration="300"/>
    <item
        android:drawable="@drawable/z_1_die_03"
        android:duration="300"/>
    <item
        android:drawable="@drawable/z_1_die_04"
        android:duration="300"/>
    <item
        android:drawable="@drawable/z_1_die_05"
        android:duration="300"/>

</animation-list>

android:oneshot 来控制动画是否循环播放, false 表示 循环播放 , true 表示 不循环播放 。

在控件的布局中给控件使用这个 drawable 文件

<ImageView
android:id="@+id/iv_frame_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/frme_animation"/>

定义好了这个动画,为了让动画播放,就要使用代码让他开始播放,代码如下:

//xml
ImageView ivFrameXml = (ImageView) findViewById(R.id.iv_frame_xml);
AnimationDrawable background = (AnimationDrawable)ivFrameXml.getDrawable();
background.start();

代码方式

代码的方式更加简单,新建一个 AnimationDrawable ,并为他增加每一帧的图片和持续时间就可以了。

//code
ImageView ivFrameCode = (ImageView) findViewById(R.id.iv_frame_code);
AnimationDrawable animationDrawable = new AnimationDrawable();
for (int i = 1; i <= 5; i++) {
    int id = getResources().getIdentifier("z_1_die_0" + i, "drawable", getPackageName());
    Drawable drawable = getResources().getDrawable(id);
    animationDrawable.addFrame(drawable,300);
}
ivFrameCode.setImageDrawable(animationDrawable);
    //循环播放
animationDrawable.setOneShot(false);
    //开始播放
animationDrawable.start();

效果如图所示:

补间动画

补间动画无须再知道动画过程中的每一帧了,只需要定义动画的开始和结束,并且指定变化的时间和方式就可以了,他会自动补全中间的过程。Android会通过所给出的开始值与结束值,再根据中间变化的规律,最后计算出每一帧图片显示的效果,最后直接显示出来。

主要包括这四种基本效果:透明度变化 Alpha 、缩放变化 Scale 、 位移变化 Translate 、旋转变化 Rotate 。这四种效果可以动态组合,从而实现复杂的动画。

插值器 Interpolator

补间动画能够自己补充中间的内容,其实靠的就是这个。

Interpolator 会根据类型不同,选择不同的算法计算出补间动画所需要动态插入的密度和位置,Interpolator 负责控制动画的变化速度,他可以 匀速、加速、减速、抛物线等多种变化。

public interface Interpolator extends TimeInterpolator {
    // A new interface, TimeInterpolator, was introduced for the new android.animation
    // package. This older Interpolator interface extends TimeInterpolator so that users of
    // the new Animator-based animations can use either the old Interpolator implementations or
    // new classes that implement TimeInterpolator directly.
}

public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}

由上面的代码可以清楚的看到一点,Interpolator 只是继承于 TimeInterpolator ,里面只是一个空实现而已。而在 TimeInterpolator 下,也只有 float getInterpolation(float input); 一个方法。input 是一个 0.0 ~ 1.0 的值 , 经过自定义的方法 ,那么只要返回适当的值,那么就能实现各种的效果。

例如下面是系统实现的先加速后减速的Interpolator。

AccelerateDecelerateInterpolator

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

当然Android SDK 中已经实现了几个 Interpolator 让开发者直接使用。

下面继续介绍动画,补间动画和逐帧动画一样,既能使用XML实现也能使用Code实现。

XML的文件应放置在 res/anim 目录上。

透明度变化 Alpha

XML

anim_tween_alpha.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"
>

<alpha
    android:repeatMode="reverse"
    android:repeatCount="-1"
    android:duration="1000"
    android:fromAlpha="0"
    android:toAlpha="1" />

</set>

android:interpolator 用来指定插值器

android:repeatMode 重复的模式

android:repeatCount="-1" 重复的次数。 -1 为无限循环。

XML写完了,就要在代码中使用他了。

ImageView ivTweenXml = (ImageView) findViewById(R.id.iv_tween_xml);
AnimationSet alphaSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_alpha);
ivTweenXml.startAnimation(alphaSet);

Code

ImageView ivTweenCode = (ImageView) findViewById(R.id.iv_tween_code);
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
alphaAnimation.setRepeatMode(Animation.REVERSE);
alphaAnimation.setRepeatCount(-1);
ivTweenCode.startAnimation(alphaAnimation);

上面都实现了透明度从0到1.

缩放变化 Scale

XML

anim_tween_scale.xml

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

    <scale
        android:duration="1000"
        android:fromXScale="0.2"
        android:fromYScale="0.2"
        android:toXScale="1"
        android:toYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="-1"
        android:repeatMode="reverse"
         />

</set>

  ImageView ivScaleXml = (ImageView) findViewById(R.id.iv_scale_xml);
  AnimationSet scaleSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_scale);
  ivScaleXml.startAnimation(scaleSet);

pivotX 中心点
直接写数字代表 控件本身的坐标系中的x的值
数字后面加了 % 例如 :50% ,代表 在本身的坐标系中的 x轴长度的50%

Code

ImageView ivScaleCode = (ImageView) findViewById(R.id.iv_scale_code);
ScaleAnimation scaleAnimation = new ScaleAnimation(0.2f, 1, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(1000);
scaleAnimation.setRepeatMode(Animation.REVERSE);
scaleAnimation.setRepeatCount(-1);
ivScaleCode.startAnimation(scaleAnimation);

位移变化 Translate

XML

anim_tween_translate.xml

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

    <translate
        android:duration="1000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="100"
        android:toYDelta="0"
        android:repeatCount="-1"
        android:repeatMode="reverse"
         />

</set>

 ImageView ivTranslateXml = (ImageView) findViewById(R.id.iv_translate_xml);
AnimationSet translateSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_translate);
ivTranslateXml.startAnimation(translateSet);

Code

  ImageView ivTranslateCode = (ImageView) findViewById(R.id.iv_translate_code);
  TranslateAnimation translateAnimation = new TranslateAnimation( 0,100,0,0);
  translateAnimation.setDuration(1000);
  translateAnimation.setRepeatMode(Animation.REVERSE);
  translateAnimation.setRepeatCount(-1);
  ivTranslateCode.startAnimation(translateAnimation);

旋转变化 Rotate

XML

anim_tween_rotate.xml

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

<rotate
    android:duration="1000"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:toXScale="1"
    android:toYScale="1"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="-1"
    android:repeatMode="reverse"
     />

</set>

ImageView ivRotateXml = (ImageView) findViewById(R.id.iv_rotate_xml);
AnimationSet rotateSet  = (AnimationSet) AnimationUtils.loadAnimati(TweenActivity.this,R.anim.anim_tween_rotate);
ivRotateXml.startAnimation(rotateSet);

Code

ImageView ivRotateCode = (ImageView) findViewById(R.id.iv_rotate_code);
RotateAnimation rotateAnimation = new RotateAnimation( 0,360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(1000);
rotateAnimation.setRepeatMode(Animation.REVERSE);
rotateAnimation.setRepeatCount(-1);
ivRotateCode.startAnimation(rotateAnimation);

组合起来

上面显示的就是每一种效果各自实现的方法,现在我们可以让这些效果组合起来。

xml

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

    <alpha
        android:duration="1000"
        android:fromAlpha="0"
        android:repeatCount="-1"
        android:repeatMode="reverse"
        android:toAlpha="1" />

    <rotate
        android:duration="1000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="-1"
        android:repeatMode="reverse"
        android:toDegrees="360"
        android:toXScale="1"
        android:toYScale="1" />


    <scale
        android:duration="1000"
        android:fromXScale="0.2"
        android:fromYScale="0.2"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="-1"
        android:repeatMode="reverse"
        android:toXScale="1"
        android:toYScale="1" />

    <translate
        android:duration="1000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:repeatCount="-1"
        android:repeatMode="reverse"
        android:toXDelta="100"
        android:toYDelta="0" />
</set>

ImageView ivTogetherXml = (ImageView) findViewById(R.id.iv_together_xml);
AnimationSet togetherSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_together);
ivTogetherXml.startAnimation(togetherSet);

Code

ImageView ivTogetherCode = (ImageView) findViewById(R.id.iv_together_code);
AnimationSet animationSet = new AnimationSet(false);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(scaleAnimation);
ivTogetherCode.startAnimation(animationSet);

效果如图所示:

监听

播放动画效果的时候我们可以做到对动画开始、结束、重复的监听。

alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            //动画开始时调用
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            //动画结束时调用
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            //动画重复时调用
        }
    });

只要在对应的位置添加自己想要的效果,那么就可以实现了。

AccelerateInterpolator 加速,开始时慢中间加速

几种自带的动画插入器

DecelerateInterpolator 减速,开始时快然后减速

AccelerateDecelerateInterolator 先加速后减速,开始结束时慢,中间加速

AnticipateInterpolator 反向,先向相反方向改变一段再加速播放

AnticipateOvershootInterpolator 反向加超越,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值

BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100

CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2* mCycles* Math.PI* input)

LinearInterpolator 线性,线性均匀改变

OvershootInterpolator超越,最后超出目的值然后缓慢改变到目的值

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容