Android动画总结(属性动画,补间动画,帧动画)

来源:互联网 发布:地图坐标编程软件 编辑:程序博客网 时间:2024/05/16 10:20

Android 动画总结

csdn图片可能有问题,可以看原文地址:

http://www.jianshu.com/p/d98e79486373

动画分类

Android中动画大概分为3类:

  1. TweenAnimation(补间动画)

    • TranslateAnimation
    • ScaleAnimation
    • RotateAnimation
    • AlphaAnimation
  2. FrameAnimation(帧动画)

  3. PropertyAnimation(属性动画)

PropertyAnimation属性动画

先来看属性动画,这是潮流,也是google推荐使用的。

属性动画和一般的View动画的重要区别在于:
1. 属性动画控制的是实实在在的属性,但是View动画只是产生一个动画,并没有改变控件的属性。
2. View动画只能控制View的属性,属性动画可以控制所有属性,只要这个属性有get/set 方法,是什么意思呢?

例如 我们查看ImageView的源码,可以看到它有一个私有属性叫 alpha,表示透明度,同时有 setAlpha()/getAlpha() 方法,所有我们就可以通过属性动画来修改ImageView的Alpha的值来完成动画。

那么问题来了,到底动画是怎么产生的呢?简单的说就是,在动画执行前你需要为动画设置初始值结束值动画时间(这是3个最基本的值),那么ValueAnimator类就可以通过这3个值计算出一串连续的数字,表示动画的过程。
例如:alpha值 from 0 to 255,如果时间设置成 255秒,那么 ValueAnimator产生的值将为每秒变化1,0,1,2,3,4,5,6…,然后将这些值通过 setAlpha() 设置给ImageView,就完成了动画。 当然这个例子比较奇葩,但是我觉得比较好理解。

那么怎么来实践我说的呢?我们来看一个例子:

ValueAnimator

这是ValueAnimator的初级用法,通过 ofFloat() 方法设置起始x坐标起始x+100起始x坐标,就是一个在x轴上一个来回100px的动画。区间是1000ms,注意为了将动画与控件相关联(动画都是需要应用到控件上),需要添加一个 AnimatorUpdateListener,这个回调就是用来产生一系列的中间值,然后我们在回调中将中间值设置给我们的ImageView,那么动画就完成了。

最后我们还是用Log将中间值都打印了出来,就更容易理解ValueAnimator就是用来产生一个值变化的序列的作用。当然这里使用的是默认的线性插值器,变化率是均匀的,如果使用其他插值器,还可以产生不均匀的效果。

float fromX = ivLogo.getTranslationX();ValueAnimator va = ValueAnimator.ofFloat(fromX, fromX + 100f, fromX);va.setDuration(1000);va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    @Override    public void onAnimationUpdate(ValueAnimator animation) {        float v = (float) animation.getAnimatedValue();        ivLogo.setTranslationX(v);        Log.d(TAG, "v:" + v);    }});va.start();

效果图:

这里写图片描述

打印出来的Log:

D/ANIMATION: v:0.0D/ANIMATION: v:0.14258027D/ANIMATION: v:0.53691864D/ANIMATION: v:1.2311637D/ANIMATION: v:2.2070706D/ANIMATION: v:3.3803642D/ANIMATION: v:4.894352...D/ANIMATION: v:84.35657D/ANIMATION: v:89.65131D/ANIMATION: v:94.66184D/ANIMATION: v:100.0D/ANIMATION: v:94.66184D/ANIMATION: v:89.651306D/ANIMATION: v:84.35657...D/ANIMATION: v:6.679535D/ANIMATION: v:4.894348D/ANIMATION: v:3.380371D/ANIMATION: v:2.2070618D/ANIMATION: v:1.2311707D/ANIMATION: v:0.53691864D/ANIMATION: v:0.14257813D/ANIMATION: v:0.0

理解了这个,我们就可以来看看下一个更加使用的类

ObjectAnimator

public final class ObjectAnimator extends ValueAnimator{...}

查看源码就知道,ObjectAnimator是继承于ValueAnimator的,ObjectAnimator使用起来更加简单,因为ValueAnimator还需要我们自己去回调,ObjectAnimator不需要写回调,只需要把要设置的属性,控件,区间等内容告诉它,它自己帮我们完成动画。

例子:

float fromX = ivLogo.getTranslationX();ObjectAnimator oa = ObjectAnimator.ofFloat(ivLogo, "translationX", fromX, fromX + 100f, fromX);oa.setDuration(300);oa.start();oa.addListener(new AnimatorListenerAdapter() {    @Override    public void onAnimationStart(Animator animation) {        super.onAnimationStart(animation);    }});

效果和使用 ValueAnimator 是一样的,所以就不贴图了。刚刚我们说不需要回调,但是这里又写了一个回调的Listener是什么意思呢?大家大可把这个删掉,我这里加上主要是为了说明如果想监听 动画结束,动画开始… 等中间过程,ObjectAnimator也可以做到。只需要添加这个 AnimatorListenerAdapter 抽象类。至于这里为什么是抽象类,大家打开源码就可以明白,为了不实现回调的所有方法,特别加了一个抽象类实现 AnimatorListener 接口,这样就可以想覆盖什么方法就覆盖什么方法,不需要全部都覆盖。这也可以理解为 设计模式中的适配器模式吧,原接口不符合我的要求,我需要一个适配器来完成转换

AnimatorSet

如果上面两个都理解了,那么这个就好理解了。AnimatorSet顾名思义就是动画的集合,我们要将几个属性动画放在一起运行,或者按照序列执行,或者按任意顺序执行都可以实现,看看例子:

ObjectAnimator oaScaleX = ObjectAnimator.ofFloat(ivLogo, "scaleX", 0, 1);ObjectAnimator oaScaleY = ObjectAnimator.ofFloat(ivLogo, "scaleY", 0, 1);ObjectAnimator oaRotation = ObjectAnimator.ofFloat(ivLogo, "rotation", 0, 360);ObjectAnimator oaAlpha = ObjectAnimator.ofFloat(ivLogo, "alpha", 1, 0);AnimatorSet as = new AnimatorSet();as.play(oaScaleX).with(oaScaleY).with(oaRotation);as.play(oaAlpha).after(oaRotation);as.setDuration(1000);as.addListener(new AnimatorListenerAdapter() {    @Override    public void onAnimationEnd(Animator animation) {        super.onAnimationEnd(animation);        ivLogo.setAlpha(1.0f);        Log.d(TAG, "finish:" + ivLogo.getAlpha());    }});as.start();

首先构造了4个 ObjectAnimator对象,分别是沿X轴变形,沿Y轴变形,旋转,透明度,然后我们让前3个一起执行,之后在执行渐变,最后添加一个动画结束回调,将Alpha设置为1,表示不透明,否则我们的控件就看不见了。

效果图:

使用xml文件配置属性动画

android的套路,一定会允许你使用xml的方式来配置动画,所以我们看看怎么配置:

ba358c4d-541e-4396-bd29-135a3be2142b.png

res 文件夹下新建文件夹 animator, 然后创建一个 动画xml文件:

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"    android:ordering="sequentially">    <objectAnimator        android:duration="2000"        android:propertyName="x"        android:valueFrom="0"        android:valueTo="200"        android:valueType="floatType" />    <objectAnimator        android:duration="2000"        android:propertyName="rotation"        android:valueFrom="0"        android:valueTo="360"        android:valueType="floatType" />    <objectAnimator        android:duration="2000"        android:propertyName="x"        android:valueFrom="200"        android:valueTo="400"        android:valueType="floatType" /></set>

android:ordering="sequentially"表示依次执行,

android:propertyName="rotation"表示修改的属性值

android:valueType="floatType"表示属性值类型

其他的都好理解了。

然后在代码中使用:

Animator animator = AnimatorInflater.loadAnimator(PropertyActivity.this, R.animator.animator_1);animator.setTarget(ivLogo);animator.start();

效果图:

test3.gif

使用插值器

我们知道 ValueAnimator就是用来产生一些动画属性中间值,但是默认是均匀变化的,插值器就是要使得产生的中间序列非均匀化,当然不仅是非均匀这么简单,还有很多特效:
下面是官网提供的一些插值器,大家都可以试试,我这里只是抛砖引玉,展示最简单的用法:

d6691284-7830-44e4-8abd-0ad2fc047b6a.png

使用方法:

float fromX = ivLogo.getTranslationX();ObjectAnimator oa = ObjectAnimator.ofFloat(ivLogo, "translationX", fromX, fromX + 100, fromX);oa.setInterpolator(new BounceInterpolator());oa.setDuration(1000);oa.start();

只比前面多了一行:oa.setInterpolator(new BounceInterpolator());

效果图:

test4.gif

TweenAnimation补间动画

如果上面的属性动画你都理解了,那么补间动画就更好理解了:

通过代码,和xml配置创建Animation

btnAnimation.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        Animation animation = new TranslateAnimation(0, 200, 0, 200);        animation.setDuration(1000);        animation.setFillAfter(true);        ivLogo.startAnimation(animation);    }});btnXml.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        Animation animation = AnimationUtils.loadAnimation(TweenActivity.this, R.anim.anim1);        animation.setDuration(1000);        animation.setFillAfter(true);        ivLogo.startAnimation(animation);    }});ivLogo.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        Log.d(TAG, "onClick");    }});

anim1.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">    <translate        android:fromXDelta="200"        android:fromYDelta="200"        android:toXDelta="0"        android:toYDelta="0" /></set>

代码很简单,看一下就明白了,这里给 ivLogo添加了一个onclick事件,是为了说明tween动画修改的不是view的真实属性,怎么说呢?如果点击第一个动画,ivLogo的位置相对于原来的位置已经偏离到 (+200, +200) 的位置,但是这个时候如果依然点击 ivLog原位置,依然会打印 “onClick”, 所以其实View的位置属性是没有变化的。所以Tween动画修改的不是属性值,而只是产生的一个动画效果而已。

效果图:

test5.gif

学习Animation的话,关注比较多的应该是Animation的一些属性设置,大家感兴趣可以参考官网。

FrameAnimation帧动画

上面两个动画都与控件相关,但是帧动画就完全是图片的叠加。原理和 gif 动画 或者电影一样,是因为每一帧过的速度太快,眼睛来不及反应所以我们觉得是动画。

anim_frame.xml

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"    android:oneshot="false">    <item        android:drawable="@drawable/logo1"        android:duration="100" />    <item        android:drawable="@drawable/logo2"        android:duration="100" />    <item        android:drawable="@drawable/logo3"        android:duration="100" />    <item        android:drawable="@drawable/logo4"        android:duration="100" />    <item        android:drawable="@drawable/logo5"        android:duration="100" />    <item        android:drawable="@drawable/logo6"        android:duration="100" /></animation-list>
  1. 根元素为 animation-list
  2. android:oneshot=”false” 表示动画一直循环执行

代码调用:

btnStart.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View v) {        ivWifi.setImageResource(R.drawable.anim_frame);        AnimationDrawable animationDrawable = (AnimationDrawable) ivWifi.getDrawable();        if (isRun) {            animationDrawable.stop();        } else {            animationDrawable.start();        }        isRun = !isRun;    }});

一个全局变量表示动画是否在执行,然后点击按钮时更换状态。

效果图:

test6.gif

总结

例子代码下载链接:
http://download.csdn.net/detail/u013647382/9648454

Android中提供了3种动画,以后的趋势还是属性动画,所以大家不要犹豫,快来钻研属性动画吧!

0 0
原创粉丝点击