android动画详解

来源:互联网 发布:edf调度算法实现 编辑:程序博客网 时间:2024/06/13 23:52


        在android 3.0以前只支持两种动画模式:一种为补间动画(tween animation)另一种为帧动画(frame animation)。在android3.0之后,系统又引入了一种新的动画系统:属性动画(property animation),对于3.0之前的系统,我们可以通过引用nineoldAndroids.jar来达到在系统中使用属性动画的目的。这三种动画模式在SDK中分别被称为property animation,view animation,drawable animation。下面我们对这三种动画进行简单的总结与介绍。 

1. View Animation(Tween Animation)

  View Animation(Tween Animation):补间动画,特性是我们只需要给出两个关键帧(通常为开始和结束帧),系统会通过一些算法将给定属性值在给定的时间内在两个关键帧间执行渐变操作。相对于帧动画,补间动画可以节省系统的内存空间。

    Tween Animation主要包括四种动画:位移动画,渐变透明动画,渐变大小动画,旋转动画。另外还可以实现这几种动画的组合。具体实现在android.view.animation类库中。

    通常,View animation只能应用于View对象,而且只支持一部分属性,不支持背景颜色的改变。另外View animation 只是改变了View对象的绘制位置,而并没有改变View的相关属性,比如:你有一个ImageView,通过位移动画,将ImageView下移了500pix,并且设置了setFillAfter(true);动画完成后,虽然视觉上,ImageView下移了,但是点击视图本身并不会触发点击事件,ImageView对象仍在它原来的位置。

  View Animation动画的定义既可以用代码定义也可以用XML定义:

   XML中                                                                    JavaCode中

   <alpha/> 渐变透明度动画效果                         AlphaAnimation

   <scale/> 渐变尺寸伸缩动画效果                     ScaleAnimation

   <translate/> 画面转换位置移动动画效果       TranslateAnimation 

   <rotate/> 画面转移旋转动画效果                     RotateAnimation

   <set/> 组合渐变。支持组合多种渐变效果      AnimationSet 

例如:我们要实现一个渐变动画:在代码中的实现方式主要是:

1,新建一个渐变透明度动画对象:

         Animation alphaAnimation = new AlphaAnimation(0.1f, 1.0f);

         //起始透明度为0.1,结束时为1.

2,设置持续时间等参数: 

        alphaAnimation.setDuration(300);//持续时间为300毫秒

3,绑定View并开启动画: mImage.startAnimation(alphaAnimation);

在XML中实现:首先在/res/anim/文件夹内定义文件:alpha_demo.xml:

<alpha  xmlns:android="http://schemas.android.com/apk/res/android"                               

     android:fromAlpha="0.1"起始透明度,0.0表示完全透明
     android:toAlpha="1.0"结束透明度,1.0表示完全不透明

     android:duration="300"/>

然后,在代码中指定相应动画:

Animation animation = AnimationUtils.loadAnimation(mContext,      

                                     R.anim.alpha_demo);        

imageView.startAnimation(animation);  

     其他几种动画使用方式和以上基本相似。另外通过在Java代码中实现动画需求会不利于代码复用,不推荐使用。但是,有些动画需要动态设置其起始位置时可以考虑使用Java代码来实现。

    用XML定义的动画,XML文件的根元素可以是各动画标签元素也可以是set标签(表示以上几个动画的集合,set可以嵌套)。默认情况下,所有动画是同时进行的,可以通过startOffset属性设置各个动画的开始时间来达到动画顺序播放的效果。

    xml中各通用属性介绍:

    android:fillAfter 是指动画结束是画面停留在此动画的最后一帧,与fillEnabled属性无关。如果是组合动画(Set),必须要在Set中设置该属性,否则无效。

    android:fillBefore fillBefore是指动画结束时画面停留在此动画的第一帧,

    android:fillEnabled 和fillBefor配合使用,默认为true。

    android:duration 表示动画持续时间,单位为毫秒。可以用来计算速度。

android:interpolator 表示变化率,一个插补属性,改变动画渐变的方式。可以将动画效果设置为加速,减速,反复,反弹等。默认为开始和结束慢中间快AccelerateDecelerateInterpolator。具体可看下SDK。

    android:startOffset 在调用start函数之后等待开始运行的时间,单位为毫秒。可以用来控制多个动画连续播放。

    android:repeatCount 重复的次数,默认为0,必须是int,可以为-1(infinite)表示不停止。

    android:repeatMode 重复的模式,默认为restart,即重头开始重新运行;为reverse即从结束开始向前重新运行。在android:repeatCount大于0或为infinite时生效。

 

 

顺便说一下常用的TranslateAnimation的三个构造函数:

1.  Public TranslateAnimation(Context context,AttributeSet attrs)     

2.  public TranslateAnimation(float fromXDelta, float toXDelta, 

                                float fromYDelta, float toYDelta)

  fromXDelta:  这个参数表示动画开始的点离当前View X坐标上的差值;

  toXDelta,    这个参数表示动画结束的点离当前View X坐标上的差值;

  fromYDelta,  这个参数表示动画开始的点离当前View Y坐标上的差值;

  toYDelta     这个参数表示动画开始的点离当前View Y坐标上的差值;

  如果view在A(x,y)点 那么动画就是从B点(x+fromXDelta, y+fromYDelta)点移动到C 点(x+toXDelta,y+toYDelta)点.

3,public  TranslateAnimation(int fromXType, float fromXValue,

                              int toXType, float toXValue, 

                              int fromYType, float fromYValue, 

                              int toYType, float toYValue)

fromXType:第一个参数是x轴方向的值的参照,

主要有三种:Animation.ABSOLUTE,    

    Animation.RELATIVE_TO_SELF,   Animation.RELATIVE_TO_PARENT

  fromXValue:第二个参数是第一个参数类型的起始值;

toXType,toXValue:第三个参数与第四个参数是x轴方向的终点参照与对应值;以此类推。

如果全部选择Animation.ABSOLUTE,其实就是第二个构造函数。

    以x轴为例介绍参照与对应值的关系:

      如果选择参照为Animation.ABSOLUTE,那么对应的值应该是具体的坐标值,比如100到300,指绝对的屏幕像素单位

      如果选择参照为Animation.RELATIVE_TO_SELF或者 Animation.RELATIVE_TO_PARENT指的是相对于自身或父控件,对应值应该理解为相对于自身或者父控件的几倍或百分之多少。

     在XML中对应android:fromXDelta,toXDelta等代表平移坐标的起始和结束位置,可以为浮点数或是百分比;后面+p(100%p)表示相对于父控件,否则相对于本身。

另外,对于位移动画,当动画结束后,View会跳回到原始位置。利用setFillAfter(true)函数设为true之后,界面会停留在动画播放完时的界面。此时动画结束后界面显示在结束的位置,但是View控件的实际位置还在起始点,和看上去的位置不对应。通常移动之前,可以首先利用offsetTopAndBottom()或者offsetLeftAndRight()函数将控件移动到我们需要的位置。对TranslateAnimation,setFillBefore默认为true,因此在动画开始前,将transformation绑定到View,然后offsetTopAndBottom()后,View依然会从原始位置开始运动。

 

补间动画应用于Activity

Activity之间切换的动画:

1,使用activity中startActivity或,finish时调用overridePendingTransition()方法配置Activity的切换动画。

overridePendingTransition(int enterAnim, int exitAnim)

参数为xml中定义的动画属性。

2,通过在AndroidManifest.xml中配置Activity的主题属性(theme),并且在自定义的theme style中配置android:windowAnimationStyle属性,指向自定义的动画style:

<!--自定义的theme style-->

<style name="ThemeActivity" parent="@android:style/Theme.NoTitleBar">

<item  

 name="android:windowAnimationStyle">@style/myAnimation</item>

</style>

<!--自定义的windowAnimationStyle,其中配置了Activity的进出动画的引用-->

<style name="myAnimation" parent="@android:style/Animation.Activity">

    <item name="android:activityOpenEnterAnimation">@anim/right_in</item>

    <item name="android:activityOpenExitAnimation">@anim/left_out</item>

    <item name="android:activityCloseEnterAnimation">@anim/left_in</item>

    <item name="android:activityCloseExitAnimation">@anim/right_out</item>

</style>

然后把mytheme这个style作为Activity的theme就可以了。

 

LayoutAnimationController 

LayoutAnimationsController用于为一个layout里面的控件,或者是一个ViewGroup里面的控件设置统一的动画效果。即用于布局和容器上面的动画

每一个控件都有相同的动画效果。

控件的动画效果可以在不同的时间显示出来。

LayoutAnimationsController可以在xml文件当中设置,也可以在代码当中进行设置。

XML:

a、设置容器控件(ViewGroup)的android:layoutAnimation属性

    第一步:在res/anim中添加animation_layout.xml文件,配置动画引用、执行顺序、延迟时间。

<?xml version="1.0" encoding="utf-8"?>

<layoutAnimation xmlns:android=http://schemas.android.com/apk/res/android

    android:animation="@anim/list_anim"

android:animationOrder="normal"(normal:顺序,random:随机,reverse:反向

android:delay="1" />(间隔时间,70%或者浮点数)

    第二步:在res/anim中添加具体的动画配置文件list_anim.xml文件

<?xml version="1.0" encoding="utf-8"?>

<translate xmlns:android=http://schemas.android.com/apk/res/android

    android:detachWallpaper="true"

    android:duration="1000"

    android:fromXDelta="0%"

    android:fromYDelta="0%"

    android:toXDelta="100%"

    android:toYDelta="100%" >

</translate>

第三步:对容器控件配置布局动画

<LinearLayout

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:id="@+id/linear"

    android:layoutAnimation="@anim/animation_layout"

    android:orientation="vertical" >

</LinearLayout>

代码中实现:

// 获取动画

Animation  animation=AnimationUtils.loadAnimation(MainActivity.this,   

                                         R.anim.list_anim);

// 创建布局动画控制器,并设置延迟时间和顺序

LayoutAnimationController controller = 

                            new LayoutAnimationController(animation);

controller.setDelay(2.0f);

controller.setOrder(LayoutAnimationController.ORDER_NORMAL);

// 给容器控件设置布局动画

viewGroup.setLayoutAnimation(controller);

最后,上述方法配置的动画会在UI初始化时执行,如果想在code中控制布局动画的执行可以使用:viewGroup.startLayoutAnimation()。

 

2. Drawable Animation(Frame Animation)

  Drawable Animation(Frame Animation):帧动画,类似GIF图片,通过一系列Drawable依次显示来模拟动画的效果。在XML中的定义文件:R.drawable.drawable_anim 如下:

<animation-list  xmlns:android="http://schemas.android.com/apk/res/android"

                 android:oneshot="true">

<itemandroid:drawable="@drawable/gif1" android:duration="200"/>

<itemandroid:drawable="@drawable/gif2" android:duration="200"/>

<itemandroid:drawable="@drawable/gif3" android:duration="200"/>

</animation-list>

以<animation-list>为根元素,以<item>表示要轮换显示的图片,duration属性表示各项显示的时间。XML文件要放在/res/drawable/目录下。代码中使用:

imageView.setBackgroundResource(R.drawable.drawable_anim);

anim = (AnimationDrawable) imageView.getBackground();

然后在适当的时机调用anim.start()开始帧动画以及anim.stop()结束。

在使用时,我们需要注意以下几点:

    1,要在代码中调用Imageview的setBackgroundResource方法,如果直接在XML布局文件中设置其src属性当触发动画时会FC。

    2,在动画start()之前要先stop(),不然在第一次动画之后会停在最后一帧,这样动画就只会触发一次。

3,不要在onCreate中调用start,因为AnimationDrawable还没有完全跟Window相关联,如果想要界面显示时就开始动画的话,可以在onWindowFoucsChanged()中调用start()。

 

3. Property Animation

  属性动画,是在Android 3.0中才引进的,它更改的是对象的实际属性,在View Animation(Tween Animation)中,其改变的是View的绘制效果,真正的View的属性保持不变,比如无论你在对话中如何缩放Button的大小,Button的有效点击区域还是没有应用动画时的区域,其位置与大小都不变。而在Property Animation中,改变的是对象的实际属性,如Button的缩放,Button的位置与大小属性值都改变了。而且Property Animation不止可以应用于View,还可以应用于任何对象。

    在Property Animation中,可以对动画应用以下属性:

    Duration:动画的持续时间,默认300毫秒。

    TimeInterpolation:时间插值。定义动画的变化率,如先快后慢

    TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值

    Repeat Country and behavoir:重复次数与以及重复模式,如播放3次、5次、无限循环,重复时从头开始还是反向循环等

    Animator sets:动画集合,即可以同时对一个对象应用几个动画,这些动画可以同时播放也可以顺序播放。也可以对不同对象设置不同动画

    Frame refreash delay:多少时间刷新一次,即每隔多少时间计算一次属性值,默认为10ms,最终刷新时间还受系统进程调度与硬件的影响

总的来说,属性动画就是动画的执行类来设置动画操作的对象的属性、持续时间,开始和结束的属性值,时间差值等,然后系统会根据设置的参数动态的变化对象的属性。

使用属性动画,我们主要是使用以下两个类:ValueAnimator,objectAnimator以及Animator sets。

 1,ValueAnimator

ValueAnimator是实现属性动画的基础类,包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。但是ValueAnimator不与View关联,需要添加监听以实现关联操作。在onAnimationUpdate中实现对Object的修改。

应用Property Animation有两个步聚:

   1,计算属性值,

   2,根据属性值执行相应的动作,如改变对象的某一属性。

  ValuAnimiator只完成了第一步工作,如果要完成第二步,需要实现ValueAnimator.onUpdateListener接口,如:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);

animation.setDuration(1000);

animation.addUpdateListener(new AnimatorUpdateListener(){    

      @Override    

      publicvoid onAnimationUpdate(ValueAnimator animation) {        

          view.setAlpha((Float)animation.getAnimatedValue());   

      }

});

animation.setInterpolator(new CycleInterpolator(3));

animation.start();

ofFloat()参数表示动画从开始到结束的位置点,如果只有一个参数,表示结束点。

 

Animation Listeners

    动画播放过程中还可以通过以下listeners来监听动画播放过程中的各个重要事件:

Animatior.AnimationListener

   1) onAnimationStart()  Called when the animation starts.

   2) onAnimationEnd()   Called when the animation ends.

   3) onAnimationRepeat()  Called when the animation repeats itself.

   4) onAnimationCancel() Called when animation is canceled and it will also call onAnimationEnd().

ValueAnimator.AnimatorUpdateListener

   1) onAnimationUpdate()  called on every frame of the animation. Implementing this listener is required if you use ValueAnimator;

通过监听这个事件在属性的值更新时执行相应的操作,对于ValueAnimator一般要监听此事件执行相应的动作,不然Animation没意义,在ObjectAnimator(继承自ValueAnimator)中会自动更新属性,如无必要不必监听。在函数中会传递一个ValueAnimator参数,通过此参数的getAnimatedValue()取得当前动画属性值。

另外需要注意的是:Animation的执行不受Activity的生命周期影响,当Animation Activity被回收后,Animation仍可继续执行,直至其设置的duration时间。所以我们应该避免在Animation的Listener中执行与Activity相关的操作。

 

   另外,我们可以继承AnimatorListenerAdapter而不是实现AnimatorListener接口来简化操作,这个类对AnimatorListener中的函数都定义了一个空函数体,这样我们就只用定义想监听的事件而不用实现每个函数却只定义一空函数体。

ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);

oa.setDuration(3000);

oa.addListener(new AnimatorListenerAdapter(){    

     publicvoid on AnimationEnd(Animator animation){        

              Log.i("Animation","end");    

     }

});

oa.start();

 

2,ObjectAnimator

  继承自ValueAnimator,它提供了与object(View)绑定的接口,动画执行过程中会自动更新属性值。使用时要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性。使用objectAnimator使得操作动画变的非常简单,实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,对象应该有一个setter函数和getter方法。

    如上面的例子中,像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法。

  如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。

  如果上述条件不满足,则不能用ObjectAnimator,应用ValueAnimator代替。

btn=(Button)findViewById(R.id.button1);

btn.setOnClickListener(new OnClickListener() {  

      @Override 

      publicvoid onClick(View v) {    

           ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);    

           oa.setDuration(3000);    

           oa.start();  

      }

});

  把一个TextView的透明度在3秒内从0变至1。

根据应用动画的对象或属性的不同,可能需要在onAnimationUpdate函数中调用invalidate()函数刷新视图。

同样也可以在XML中实现属性动画:

首先在res/animator/文件目录下,定义XML文件:

<objectAnimator

xmlns:android=http://schemas.android.com/apk/res/android

    android:propertyName="alpha"

    android:duration="1000"

    android:valueFrom="0.0"

    android:valueTo="1.0"

    android:valueType="floatType">

</objectAnimator>

 

接着在Java文件中,获取到动画对象:

ObjectAnimator animator =   (ObjectAnimator)AnimatorInflater.loadAnimator

                                               (this,R.animator.object_animator);

animator.setTarget(view);     // xml中无法绑定View,这一步必须在code中执行。

animator.start();

 

通过AnimationSet应用多个动画

  AnimationSet和AnimationSet类似,提供了一系列动画集,并可设置组中动画的时序关系,如同时播放,顺序播放等。

  以下例子同时应用5个动画:

    播放anim1;然后同时播放anim2,anim3,anim4;最后播放anim5:

AnimatorSet animSet= newAnimatorSet();

animSet.play(anim1).before(anim2);

animSet.play(anim2).with(anim3);

animSet.play(anim2).with(anim4)

或者:animSet.playTogether(anim2,anim3,anim4)

animSet.play(anim5).after(amin2);

animSet.start();

 

PropertyValuesHolder

用来封装属性以及其对应的动画节点。

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f); //可以1~n

PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);

ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY).start();

 

Keyframe

它也是一个属性动画的辅助类,封装了时间、属性值的键值对。通过它可以定义一个在特定时间的特定状态,而且在两个keyFrame之间可以定义不同的Interpolator,相当多个动画的拼接,第一个动画的结束点是第二个动画的开始点。将ObjectAnimator分割成了两段,每段可以有不同的interpolater:

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);

Keyframe kf1 = Keyframe.ofFloat(0.5f, 360f);

Keyframe kf2 = Keyframe.ofFloat(1f, 0f);

PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);

ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(view, pvhRotation);

rotationAnim.setDuration(5000);

 

 

当Layout改变时应用动画

ViewGroup中的子元素可以通过setVisibility使其Visible、Invisible或Gone,当有子元素可见性改变时,可以向其应用动画,通过LayoutTransition类应用此类动画:

LayoutTransition Transition = new LayoutTransition();

transition.setAnimator(LayoutTransition.DISAPPEARING, customAnim);

mViewGroup . setLayoutTransition(mTransitioner)

  通过setAnimator应用动画,第一个参数表示应用的情境,有4种类型:

APPEARING        当一个元素变为Visible时对其应用的动画

CHANGE_APPEARING   当一个元素变为Visible时,因系统要重新布局有 

                 一些元素需要移动,这些要移动的元素应用的动画

DISAPPEARING      当一个元素变为InVisible时对其应用的动画

CHANGE_DISAPPEARING 当一个元素变为Gone时,因系统要重新布局有一

                 些元素需要移动,这些要移动的元素应用的动画   

第二个参数为自己定义的Animator。

    当然,如果要使用默认的动画,一个非常简单的方式是在ViewGroup的XML布局文件中把android:animateLayoutchanges 属性设置为true。

 

ViewPropertyAnimator

    View自身封装的一个动画类。其中封装了平移、缩放、旋转、渐显等动画效果。如果需要对一个View的多个属性进行动画可以用ViewPropertyAnimator类,该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图,相对View自身的动画类实现方法,使用ViewPropertyAnimator更加高效、快捷。

 

0 0
原创粉丝点击