首页 > 代码库 > Android动画浅析

Android动画浅析

前言

在应用的开发中,动画是必不可少的一部分,否则很多视觉效果会显得特别突兀。今天我们就来了解一下Android中的动画库。

动画的分类

Android平台为我们提供了两类动画,Tween(补间动画)动画和Frame(帧)动画。Tween动画是通过对场景中的对象不断进行图像变换(平移、缩放、旋转等)来产生动画效果的;Frame动画则是顺序播放事先做好的每帧图像,类似于快速的幻灯片一样。

补间动画

Tween动画是通过预先定义一个动画,这个动画指定了图形变换的类型(旋转、平移、缩放等)、启动时间、持续时间、起始值,在View绘制时就会沿着时间线修改这些属性值,从而达到动画效果。动画可以通过代码定义,也可以通过xml来定义。如果动画是在xml中定义的,那么使用AnimationUtils.loadAnimation(context, R.anim.your_anim);来加载即可。

Alpha:透明度动画

该动画是在指定的时间段内修改View的透明度,从0.3到1.0f的透明度动画示例如下 :
代码定义动画 :
  AlphaAnimation alphaAnimation = new AlphaAnimation(0.3f, 1.0f) ;
        alphaAnimation.setDuration(1000);
xml 定义动画:
<?xml version="1.0" encoding="utf-8"?>  
    <!-- 透明度 -->  
    <alpha  xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromAlpha="1"  
        android:toAlpha="0"   
        android:duration="1000"  
        />  
然后执行通过view的setAnimation或者startAnimation设置动画即可。

Scale:缩放动画

对view的缩放动画,需要指定x, y轴上各自的缩放值。示例为在一秒中之内把View缩放为原来的一半大小,缩放的中心点为view的中心。
代码定义动画:
        ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.5f, 1.0f, 0.5f,0.5f, 0.5f);
        scaleAnimation.setDuration(1000);
xml 定义动画: 
<?xml version="1.0" encoding="utf-8"?>  
 
    <!-- 缩放 -->  
    <scale  xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromXScale="1"   
        android:fromYScale="1"   
        android:toXScale="0.5"   
        android:toYScale="0.5"   
        android:pivotX="0.5"  
        android:pivotY="0.5"  
        android:duration="3000"   
        /> 

Translate:位移动画

位移动画是将View从一个点移动到某一个点的动画。例如将view在一秒钟内从(0,0)位置移动到(100, 100)位置。
代码定义:
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 100, 0, 100) ;
        translateAnimation.setDuration(1000);

XML定义动画 :
<?xml version="1.0" encoding="utf-8"?>

 <!-- 移动 -->  
    <translate   xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromXDelta="0"  
        android:fromYDelta="0"  
        android:toXDelta="100"  
        android:toYDelta="100"   
        android:duration="000"   
        />  

Rotate:旋转动画

旋转动画负责对view的角度进行调整,例如将view从当前角度旋转360度。
代码定义:
  RotateAnimation rotateAnimation = new RotateAnimation(0, 360) ;
        rotateAnimation.setDuration(1000);
XML定义:
<?xml version="1.0" encoding="utf-8"?>  
    <!-- 旋转 -->  
    <rotate  xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromDegrees="0"  
        android:toDegrees="360"  
        android:pivotX="50%"  
        android:pivotY="50%"   
        android:duration="1000"   
        /> 


帧动画

帧动画可以想象为一部很短的电影,他由数量有限的关键帧组成,当这个帧动画时这些关键帧快速的切换,从而达到动画的效果。

<?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/p1" android:duration="200" />
    <item android:drawable="@drawable/p2" android:duration="200" />
    <item android:drawable="@drawable/p3" android:duration="200" />
    <item android:drawable="@drawable/p4" android:duration="200" />
    <item android:drawable="@drawable/p5" android:duration="200" />
    <item android:drawable="@drawable/p6" android:duration="200" />
    <item android:drawable="@drawable/p7" android:duration="800" />
    <item android:drawable="@drawable/p8" android:duration="200" />
    <item android:drawable="@drawable/p9" android:duration="200" />
    <item android:drawable="@drawable/p10" android:duration="200" />
    <item android:drawable="@drawable/p11" android:duration="200" />
</animation-list>
使用帧动画与补间动画不太一样,示例如下 : 

 // 通过逐帧动画的资源文件获得AnimationDrawable示例    AnimationDrawable frameAnim = (AnimationDrawable) getResources().getDrawable(R.drawable.my_frame_anim);
// 把AnimationDrawable设置为myView的背景
myView.setBackgroundDrawable(frameAnim);

动画的插值器(Interpolator)

在补间动画中,我们一般只定义首帧和尾帧,然后由系统自动生成中间帧,生成中间帧的这个过程可以成为“插值”。插值器的作用是告诉动画某个属性(比如颜色的渐变)如何随时间变化 ,在duration周期内每个时刻对应的属性值。下面是几种常见的插值器:


android 系统默认支持AccelerateDecelerateInterpolator 、 AccelerateInterpolator 、 AnticipateInterpolator 、AnticipateOverShootInterpolator 、 BounceInterpolator 、 CycleInterpolator 、DecelerateInerpolator 、 LinearInterpolator 、 OverShootInterpolator 共 9 种插值器(若这些插值器不能满足需求,则可以自定义插值器)。

例如,一个alpha动画在一秒内从0.0f到1.0f变换,线性插值器的动画为匀速执行的。但是加速插值器的动画会随着时间的增加而越来越快。

插值器通过getInterpolation方法获得插值因子,插值因子的计算也在此函数中完成。例如线性插值器,它的动画则是匀速运动的,因此在它的getInterpolation函数中插值因子只跟时间相关,与其他因素无关。getInterpolation(int inpput)函数中的参数即动画执行的百分比,也可以认为是动画已经执行时间和动画周期的百分比。该值为0.0f 到 1.0f,即动画的开始到结束。

/**
 * An interpolator where the rate of change is constant
 *
 */
public class LinearInterpolator implements Interpolator {

    public LinearInterpolator() {
    }
    
    public LinearInterpolator(Context context, AttributeSet attrs) {
    }
    
    public float getInterpolation(float input) {
        return input;
    }
}
再看加速插值器,即动画的速度会随着时间的推移而越来越快。我们看看它的getInterpolation实现:

    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }
默认情况下mFactor会为1.0f, 随着动画的执行,input慢慢增大,getInterpolation函数返回的数值的大小变化范围会越来越大,从而导致动画变快。

使用矩阵Matrix自定义动画

自定义动画时,我们主要就是覆写applyTransformation(float interpolatedTime, Transformation t) 方法,在方法是在动画执行时就是调用该方法来实现动画操作,我们在这里需要实现修改alpha, 缩放,平移等动画。interpolatedTime是由插值器计算出来的因子,由动画的执行百分比与插值器的策略计算而来,值为0.0f 到 1.0f。参数t为矩阵变换的封装类。在这里我们只讨论使用矩阵实现的自定义动画。例如,我们需要定制一个动画,是它能够在低于API 11 版本的系统里实现Y轴的旋转动画,android中的RorateAnimation动画只支持在Z轴上的旋转动画,这是我们就可以通过矩阵来实现。关于矩阵的资料,请移步,Android中图像变换Matrix的原理、代码验证和应用(一)Android Matrix理论与应用详解Android--Matrix图片变换处理


/**
 * @author mrsimple
 */
public class RotateYAnimation extends Animation {

    private int halfWidth;

    private int halfHeight;
    // 使用Camera实现3D旋转
    Camera mCamera = new Camera();
    // 
    protected float mRotateY = 0.0f;

    /**
     * width,height为执行该动画的view的宽度、高度。后面两个参数为执行该动画的view的parent的宽度、高度
     */
    @Override
    public void initialize(int width, int height, int parentWidth,
            int parentHeight) {

        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(2000);
        setFillAfter(true);

        halfWidth = width / 2;
        halfHeight = height / 2;
        setInterpolator(new LinearInterpolator());
    }

    // 设置旋转角度
    public void setRotateY(float rorateY) {
        mRotateY = rorateY;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {

        final Matrix matrix = t.getMatrix();
        mCamera.save();
        // 使用Camera设置旋转的角度
        mCamera.rotateY(mRotateY * interpolatedTime);
        // 将旋转变换应用到matrix上
        mCamera.getMatrix(matrix);
        mCamera.restore();
        
        // 在变换前,将动画的中心点从默认的(0,0)移动(0, -halfHeight)
        matrix.preTranslate(0, -halfHeight);
        // 变换后再从(-halfWidth, -halfHeight)移动halfWidth,halfHeight,使之再次回到(0,0)
        matrix.postTranslate(0, halfHeight);

        // View view;
    }
}

使用代码 : 

               Button btn = new Button(MainActivity.this) ;
                btn.setText("RotateY");
                MyAnimation animation = new MyAnimation();
                animation.setRotateY(45f);
                animation.setDuration(2000);
		// 启动动画
                btn.startAnimation(animation);  
效果  (效果图中的view并不是button,是我另外例子中的view): 



Android动画浅析