Android动画(一)之View动画

一、概述

Android的动画可以分为三种:View动画、帧动画和属性动画。本文中主要对View动画进行简单的概括与介绍,其实帧动画也属于View动画的一种,只不过它和平移、旋转等常见的View动画在表现形式上略有不同而已。

View动画是通过对场景里的对象不断做图像变换(平移、缩放、旋转、透明度)从而产生动画效果,它是一种渐进式动画,并且View动画支持自定义

View动画的作用对象是View,它支持4种动画效果,分别是平移动画,缩放动画、旋转动画和透明度动画。上面提到过帧动画也属于View动画,为了更好的区分这四种变换和帧动画,在 本文中如果没有特殊说明,那么所提到的View动画均指这四种变换,帧动画在后面会单独介绍。下面开始正文:

二、View动画的种类

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

名称 标签 子类 效果
平移动画 TranslateAnimation 移动View
缩放动画 ScaleAnimation 放大或缩小View
旋转动画 RotateAnimation 旋转View
透明度动画 AlphaAnimation 改变View的透明度

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





    

    
    
    
    
    
    
    
        ...
    

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

标签表示动画集合,对应AnimationSet类,它可以包含若干个动画,并且它的内部也是可以嵌套其他动画集合的,它的两个属性含义如下:

  • android:interpolator
    表示动画集合所采用的的插值器,插值器影响动画的速度,比如非均匀动画就需要通过插值器来控制动画的播放过程。这个属性可以不指定,默认为@android:anim/interpolator_resource,即加速插值器
  • android:shareInterpolator
    表示集合中的动画是否和集合共享同一个插值器。如果集合不指定插值器,那么子动画就需要单独指定插值器或使用默认值。

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

  • android:fromXDelta ---- 表示X的起始值,比如0;
  • android:toXDelta ---- 表示X的结束值,比如100;
  • android:fromYDelta ---- 表示Y的起始值;
  • android:toYDelta ---- 表示Y的结束值;

标签表示缩放动画,对应ScaleAnimation,它可以使View具有放大或缩小的动画效果,它的一系列属性的含义如下:

  • android:fromXScale ---- 水平方向缩放的起始值,比如0.5;
  • avandroid:toXScale ---- 水平方向缩放的结束值,比如1.2;
  • android:fromYScale ---- 竖直方向缩放的起始值;
  • android:toYScale ---- 竖直方向缩放的结束值;
  • android:pivotX ---- 缩放的轴点的x坐标,它会影响缩放的效果;
  • android:pivotY ---- 缩放的轴点的Y坐标,它会影响缩放的效果;

上面提到了轴点的概念,举个例子,默认情况下轴点是View的中心,这时在水平方向进行缩放的话会导致View向左右两个方向同时进行缩放,但是如果把轴点设为View的右边界,那么View就只会向左边进行缩放,反之则会向右边进行缩放。

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

  • android:fromDegrees ---- 旋转开始的角度,比如0;
  • android:toDegrees ---- 旋转结束的角度,比如180;
  • android:pivotX ---- 旋转的轴点的x坐标;
  • android:pivotY ---- 旋转的轴点的y坐标;

在旋转动画中也有轴点的概念,它也会影响旋转的具体效果。在旋转动画中,轴点扮演着旋转轴的角色,即View是围绕着轴点进行旋转的。

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

  • android:fromAlpha ---- 表示透明度的起始值,比如0.1;
  • android:toAlpha ---- 表示透明度的结束值,比如1;

上面介绍了View动画的XML格式。除了上面介绍的属性以外,View动画还有一些常用的属性,如下所示:

  • android:duration ---- 动画持续时间,单位毫秒;
  • android:fillAfter ---- 动画结束以后View是否停留在结束位置,true表示View停留在结束位置,false则不停留。

下面是一个实际的例子:

// res/anim/view_animation.xml



    

    


使用方法:

TextView textView = findViewById(R.id.mTextView);
Animation animation = AnimationUtils.loadAnimation(this,R.anim.view_animation);
textView.startAnimation(animation);

除了在XML中定义动画外,还可以通过代码来应用动画,这里举个例子:

TextView textView = findViewById(R.id.mTextView);
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(300);
textView.startAnimation(alphaAnimation);

在上面的代码中,创建了一个透明度动画,将一个TextView的透明度在300ms内由0变为1,其他类型的View动画也可以通过代码来创建,这里就不做介绍了。另外,通过AnimationsetAnimationListener方法可以给View动画添加过程监听,接口如下所示。从接口的定义可以很清楚地看出每个方法的含义。

public static interface AnimationListener {
  
    void onAnimationStart(Animation animation);

    void onAnimationEnd(Animation animation);
   
    void onAnimationRepeat(Animation animation);
}

三、自定义View动画

除了系统提供的四种View动画外,我们还可以自定义View动画。自定义动画是一件既简单又复杂的事情,说它简单是因为派生一种新动画只需要继承Animation这个抽象类,然后重写它的initializeapplyTransformation方法,在initialize方法中做一些初始化工作,在applyTransformation中进行响应的矩阵变换即可,很多时候需要采用Camera来简化矩阵变换的过程。说它复杂,是因为定义View动画的过程主要是矩阵变换的过程,而矩阵变换是数学上的概念,如果对这方面的知识不熟悉的话,就会觉得这个过程比较复杂了。

一般来说,在实际开发中很少用到自定义View动画。这里提供一个自定义View动画的例子,这个例子来自于AndroidApiDemos中的一个自定义View动画Rotate3dAnimationRotate3Animation可以围绕y周旋转并且同时沿着z轴平移从而实现一种类似于3D的效果,它的代码如下:

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;

    /**
     * Create 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,defined 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) {
        this.mFromDegrees = fromDegrees;
        this.mToDegrees = toDegrees;
        this.mCenterX = centerX;
        this.mCenterY = centerY;
        this.mDepthZ = depthZ;
        this.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();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();

        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);

    }
}

四、帧动画

帧动画是顺序播放一组预先定义好的图片,类似电影播放,不同于View动画,系统提供了另一个类AnimationDrawable来使用帧动画。帧动画的使用比较简单,首先需要通过XML来定义一个AnimationDrawable,如下所示:

// res/drawable/frame_animation.xml



    
    
    
    
    

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

TextView textView = findViewById(R.id.mTextView);
textView.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable drawable = (AnimationDrawable) textView.getBackground();
drawable.start();

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

五、使用动画的注意事项

通过动画可以实现一些比较绚丽的效果,但是在使用过程中,也需要注意一些事情,主要分为下面几类:

  1. OOM问题
    这个问题主要出现在帧动画中,当图片数量较多且图片较大时就极易出现OOM,这在实际的开发中要尤其注意,尽量避免使用帧动画。
  2. 内存泄漏
    在属性动画中有一类无限循环的动画,这类动画需要在Activity退出时及时停止,否则将导致Activity无法释放从而造成内存泄漏,通过验证后发现View动画并不存在此问题。
  3. 兼容性问题
    动画在 3.0 以下的系统上有兼容性问题,在某些特殊场景可能无法正常工作,因此需要做好适配工作。
  4. View动画的问题
    View动画是对View的影像做动画,并不是真正的改变View的状态,因此有时候会出现动画完成后View无法隐藏的现象,即setVisibility(View.GONE)失效了,这个时候只要调用view.clearAnimation()清除View动画即可解决此问题。
  5. 不要使用 px
    在进行动画的过程中,要尽量使用dp,使用px会导致在不同的设备上有不同的效果。
  6. 动画元素的交互
    view移动(平移)后,在Android 3.0以前的系统上,不管是View动画还是属性动画,新位置均无法触发单击事件,同时,老位置仍然可以触发点击事件。尽管View已经在视觉上已经不存在了,将View移回原位置后,原位置的单击事件继续生效。从 3.0开始,属性动画的单击事件触发位置为移动后的位置,但是View动画仍然在原处。
  7. 硬件加速
    使用动画的过程中,建议开启硬件加速,这样会提高动画的流畅性。

相关推荐:Android动画(二)之View动画的特殊使用场景,Android动画(三)之插值器和估值器

你可能感兴趣的:(Android动画(一)之View动画)