Android动画浅析

来源:互联网 发布:小米笔记本安装linux 编辑:程序博客网 时间:2024/05/17 00:55

前言

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


View中实现动画的过程

View的alpha动画直接通过setAlpha(float al)函数来修改透明度实现,缩放、平移、旋转等都是通过图形矩阵变换来实现。图形变换是图形学中基本知识,简单来说就是,每种变换都是一次矩阵运算。在Android中,Canvas类包含当前矩阵,当前调用Canvas.drawBitmap(bm,x,y,Paint)绘制时,android会先把bmp做一次矩阵运算,然后将运算结果显示在Canvas上。这样编程人员只需不断修改Canvas的矩阵并刷新屏幕,View里对象就会不停的做图形变换,动画就形成了。

    View设置动画,设置动画属性,在动画启动时,会调用invalidate方法重绘View。从而触发onDraw函数;在onDraw函数中,调用动画的getTransformation方法,得到当前时间点的矩阵,getTransformation函数又会调用动画的applyTransformation函数,applyTransformation函数通过一个计算因子 (由插值器通过动画执行的百分比计算出来的因子)来计算当前时刻View属性的值,修改View的属性达到图形变换。View会判断getTransformation的返回值,若为真,说明动画未完成,调用invalidate方法刷新屏幕,重绘View,从而进入下一帧动画,再次执行上述过程;若为假,说明动画完成。


动画的分类

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): 



1 0