Android的动画可以分为三种:View动画、帧动画和属性动画,其实帧动画也属于View动画的一种,只不过它和平移、旋转等常见的View动画在表现形式上略有不同而已。Vie为动画通过对场景里的对象不断做图像变换(平移、缩放、旋转、透明度)从而产生动画效果,它是一种渐进式动画,并且View动画支持自定义。帧动画通过顺序播放一些列图像从而产生动画效果,可以简单地理解为图片切换动画,很显然,如果图片过多过大就会导致OOM。属性动画通过动态地改变对象的属性从而达到动画效果,属性动画为API11的新特性,在低版本无法直接使用属性动画,但是我们仍然可以通过兼容库来使用它。在本章中,首先简单介绍View动画以及自定义View动画的方式,接着介绍View动画的一些特殊的使用场景,最后对属性动画做一个全面性的介绍,另外还介绍使用动画的一些注意事项。

View动画的作用对象是View,它支持4种动画效果,分别是平移动画、缩放动画、旋转动画和透明度动画。除了这四种典型的变换效果外,帧动画也属于View动画,但是帧动画的表现形式和上面的四种变换效果不太一样。为了更好地区分这四种变换和帧动画,在本章中如果没有特殊说明,那么所提到的View动画均指这四种变换,帧动画会单独介绍。本节将介绍View动画的四种效果以及帧动画,同时还会介绍自定义动画的方法。

1.View动画的种类

View动画的四种变换效果对应着Animation的四个子类:TranslationAnimation、ScaleAnimation、RotateAnimation和AlphaAnimation,如下表所示。这四种动画既可以通过XML来定义,也可以通过代码来动态创建,对于View动画来说,建议采用XML来定义动画,这时因为XML格式的动画可读性好。

android 动画框架 android view动画_android 动画框架

要使用View动画,首先要创建动画的XML文件,这个文件的路径为res/anim/filename.xml。View动画的描述文件是由固定的语法的,如下所示。

<?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:fromXDelta="float" android:toXDelta="float" android:fromYDelta="float" android:toYDelta="float"/> <rotate android:fromDegrees="float" android:toDegrees="float" android:pivotX="float" android:pivotY="float"/> <set> ... </set> </set>


从上面的语法可以看出,View动画既可以是单个动画,也可以由一些列动画组成。

<set>标签表示动画集合,对于AnimationSet类,它可以包含若干个动画,并且它的内部也是可以嵌套其他动画集合的,它的属性android:shareInterpolator含义:表示集合中的动画是否和集合共同享用一个插值器。如果集合不指定插值器,那么子动画就需要单独指定所需的插值器或者使用默认值;android:interpolator:表示动画集合所采用的插值器,插值器影响动画的速度,比如非匀速动画就是需要通过插值器来控制动画的播放过程。这个事项可以不指定,默认为@android:anim/accelerate_decelerate_interpolator,即加速减速插值器,关于插值器的概念会在下面进行具体介绍。

<translate>标签标示平移动画,对应TranslateAnimation类,它可以使一个View再水平和竖直方向完成平移的动画效果,它的一些列属性的含义如下:

android:fromXDetla——表示x起始值,比如0;
android:toXDelta——表示x的结束值,比如100;
android:fromYDelta——表示y的起始值。
android:toYDelta——表示y的结束值。


<scale>标签表示缩放动画,对于ScaleAnimation,它可以使View具有放大活缩小的动画效果,它的一些列属性的含义如下:



android:fromXScale——表示x起始值,比如0;

android:toXScale——表示x的结束值,比如100;

android:fromYScale——表示y的起始值。

android:toYScale——表示y的结束值。


android:pivotX——缩放的轴点x坐标,它会影响缩放的效果。

android:pivotY——缩放的轴点y坐标,它会影响缩放的效果。

在<scale>标签中提到了轴点的概念,这里举个例子,默认情况下轴点是View的中心点,这个时候在水平方向进行缩放的话会导致View就只会向坐标进行缩放,反之则向右边进行缩放,具体效果读者可以自己测试一下。


<rotate>标签表示旋转动画,对于RotateAnimation,它可以使用View具有旋转的动画效果,它的属性含义如下:

android:fromDegrees——旋转开始的角度,比如0;

android:toDegrees——旋转结束的角度,比如180;

android:pivotX——旋转的轴点x坐标。 旋转 的轴点y坐标。 在旋转动画中也有轴点的概念,它也会影响到旋转的具体效果。在旋转动画中,轴点扮演着旋转轴的角色,即View是围绕着轴点进行旋转的,默认情况下轴点为View的中心。考虑一种情况,View围绕着自己的中心点和围绕着自己的左上角旋转90度显然是不同的旋转轨迹,不同轴点对旋转效果的影响可以自己测试一下。


<alpha>标签表示透明度动画,对于AlphaAnimation,它可以改变View的透明度,它的属性含义如下:


android:fromAlpha——表示透明度的起始值,比如0.1;

android:toAlpha——表示透明度的结束值,比如1;


上面简单介绍了View动画的XML格式,具体的使用方法查看相关文档。除了上面介绍的属性以外,View动画还有一些常用的属性,如下所示。

android:duration——动画的持续时间;


android:fillAfter——动画结束以后View是否在结束位置,true表示停留在结束为止,false则不停留。

下面是一个实际的例子:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true"
    android:zAdjustment="normal">

    <translate android:fromXDelta="0"
        android:toXDelta="100"
        android:fromYDelta="0"
        android:toYDelta="100"
        android:duration="100"
        android:interpolator="@android:anim/linear_interpolator"/>
    <rotate android:fromDegrees="0"
        android:toDegrees="90"
        android:duration="400"/>
</set>


如何应用上面的动画呢?也很简单,如下所示。


Button button = (Button)findViewById(R.id.button1);
        Animation animation = AnimationUtils.loadAnimation(this,R.anim.examp1);
        button.startAnimation(animation);


另外,通过Animation的setAnimationListener方法可以给View动画添加过程监听,接口如下所示。从接口的定义可以很清楚的看出每个方法的含义。


public static interface AnimationListener {
        /**
         * <p>Notifies the start of the animation.</p>
         *
         * @param animation The started animation.
         */
        void onAnimationStart(Animation animation);

        /**
         * <p>Notifies the end of the animation. This callback is not invoked
         * for animations with repeat count set to INFINITE.</p>
         *
         * @param animation The animation which reached its end.
         */
        void onAnimationEnd(Animation animation);

        /**
         * <p>Notifies the repetition of the animation.</p>
         *
         * @param animation The animation which was repeated.
         */
        void onAnimationRepeat(Animation animation);
    }

2.自定义View动画


initialize方法中做一些初始化工作,在 applyTransformation方法中进行相应的矩阵变换即可,很多时候需要采用Camera来简化矩阵变换的过程。说他复杂,是因为自定义View动画的过程主要是矩阵变换的过程,而矩阵变换是数学上的概念,如果对这方面的知识不熟悉的话,就会觉得这个过程比较复杂了。


Rotate3dAnimation可以绕着y轴旋转并且同时沿着z轴平移从而实现一种类似于3D的效果,它的代码如下:


/**
 * An animation that rotates the view on the Y axis between two specified
 * angles. This animation also adds a translation on the Z axis (depth) to
 * improve the effect.
 */
public class Rotate3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair of
     * X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length of
     * the translation can be specified, as well as whether the translation
     * should be reversed in time.
     * 
     * @param fromDegrees
     *            the start angle of the 3D rotation
     * @param toDegrees
     *            the end angle of the 3D rotation
     * @param centerX
     *            the X center of the 3D rotation
     * @param centerY
     *            the Y center of the 3D rotation
     * @param reverse
     *            true if the translation should be reversed, false otherwise
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ,
            boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;
        final Matrix matrix = t.getMatrix();
        // 将当前的摄像头位置保存下来,以便变换进行完成后恢复成原位,
        camera.save();
        // camera.translate,这个方法接受3个参数,分别是x,y,z三个轴的偏移量,我们这里只将z轴进行了偏移,
        if (mReverse) {
            // z的偏移会越来越大。这就会形成这样一个效果,view从近到远
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            // z的偏移会越来越小。这就会形成这样一个效果,我们的View从一个很远的地方向我们移过来,越来越近,最终移到了我们的窗口上面~
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }

        // 是给我们的View加上旋转效果,在移动的过程中,视图还会移Y轴为中心进行旋转。
        camera.rotateY(degrees);
        // 是给我们的View加上旋转效果,在移动的过程中,视图还会移X轴为中心进行旋转。
        // camera.rotateX(degrees);

        // 这个是将我们刚才定义的一系列变换应用到变换矩阵上面,调用完这句之后,我们就可以将camera的位置恢复了,以便下一次再使用。
        camera.getMatrix(matrix);
        // camera位置恢复
        camera.restore();

        // 以View的中心点为旋转中心,如果不加这两句,就是以(0,0)点为旋转中心
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

3.帧动画


AnimationDrawable,如下所示。


<?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/image1" android:duration="500"/>
    <item android:drawable="@drawable/image2" android:duration="500"/>
    <item android:drawable="@drawable/image3" android:duration="500"/>
</animation-list>


然后将上述的Drawable作为View的背景并通过Drawable来播放动画即可:


final Button button = (Button)findViewById(R.id.button1);
        button.setBackgroundResource(R.drawable.frame_animation);
        AnimationDrawable drawable = (AnimationDrawable)button.getBackground();
        drawable.start();


帧动画的使用比较简单,但是比较容易引起OOM,所以在使用帧动画时尽量避免使用过多尺寸较大的图片。