zoukankan      html  css  js  c++  java
  • Android动画全解

    在Android开发中经常会碰到动画,看到别的应用有很酷炫的应用时,总是想怎么去实现,但是每次都是发现感觉是知道怎么做的,实际做起来还是无从下手的感觉,究其原因还是

    Android动画方面的知识不全面,这几天利用空闲时间研究了下Android动画知识,当作学习日记,大家也好有所借鉴。

    Android主要分三类动画:Tween Animation、Frame Animation、Property Animation。

    其中Tween Animation、Frame Animation是在Android是在Android3.0之前就有的动画技术,后来由于动画需求越来越高,Tween Animation、Frame Animation已经满足不了应用对于动画效果的需求了,于是在Android3.0之后,谷歌又增加了新的动画Property Animation。下面对这三种动画逐个介绍。

    一、Tween Animation

    中文亦叫补间动画,它是通过平移、旋转、缩放以及修改透明度来达到动画效果的,原理是给出两个关键帧,通过一些算法将给定属性值在给定时间内在两个关键帧间渐变。这里我们只关心动画的使用,不关注它的代码实现。Tween Animation基于Animation类扩展,有以下几个Tween Animation类:TranslateAnimation(平移)、AlphaAnimation(透明度)、ScaleAnimation(缩 放)、RotateAnimation(旋转)。

    TranslateAnimation使用方法如下:

    private TranslateAnimation mTranslateAnimation;
    //这四个参数含义分别是当前View x起点坐标、x终点坐标、y起点坐标、y终点坐标
    mTranslateAnimation = new TranslateAnimation(0, 200, 0, 0);
    //动画持续时间
    mTranslateAnimation.setDuration(2000);
    //重复次数
    mTranslateAnimation.setRepeatCount(1);
    //动画执行模式
    mTranslateAnimation.setRepeatMode(Animation.REVERSE);

    以上代码含义为从view的起点开始,保持y轴不变,沿着x平移200个像素,平移时间为2秒,重复执行一次,第二次执行方式与第一次执行方式完全相反,如下图:

    以上是java代码实现的方式,亦可以使用xml实现,如下:

    /res/anim/translate.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:fromXDelta="0"
            android:toXDelta="200"
            android:fromYDelta="0"
            android:toYDelta="0"
            android:duration="2000"
            android:repeatCount="1"
            android:repeatMode="reverse"
            android:interpolator="@android:anim/accelerate_decelerate_interpolator"/>
    </set>

    fromXDelta:View x轴起点

    toXDelta:View x轴终点

    fromYDelta:View y轴起点

    toYDelta:View y轴终点

    duration:动画持续时间

    repeatCount:动画执行次数

    repeatMode:动画执行模式

    interpolator:插值器,可以理解为View动画值的改变规律

    java中调用:

    private Animation mTranslateAnimation;
    mTranslateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate);
    mTranslateIv.startAnimation(mTranslateAnimation);

    使用Java或者xml实现动画并无什么不同,采用哪种完全取决于自己的编程习惯,但如果单纯从扩展性来说,显然xml方式更占优。

    AlphaAnimation使用方法如下:

    private AlphaAnimation mAlphaAnimation;
    //不透明度从100%到0
    mAlphaAnimation = new AlphaAnimation(1, 0);
    mAlphaAnimation.setDuration(2000);
    mAlphaAnimation.setRepeatCount(1);
    mAlphaAnimation.setRepeatMode(Animation.REVERSE);

    以上代码含义是在2秒内将View的不透名度从1变为0,总共执行2次,第一次和第二次执行动画过程相反,效果如下图:

    xml实现方法可参照TranslateAnimation

    ScaleAnimation使用方法如下:

    mScaleAnimation = new ScaleAnimation(1, 2, 1, 2);
    mScaleAnimation.setDuration(2000);
    mScaleAnimation.setRepeatCount(1);
    mScaleAnimation.setRepeatMode(Animation.REVERSE);

    上面ScaleAnimation构造函数中四个参数分别是:

    fromX:起始x方向大小

    toX:最终x方向大小

    fromY:起始y坐标

    toY:最终y坐标

    上面代码含义为将View在2秒内横竖方向增大一倍,第二次是在原来的基础上缩小一倍,效果图如下:

    xml实现方法同参照TranslateAnimation

    RotateAnimation使用方法如下:

    mRotateAnimation = new RotateAnimation(0, 360);
    mRotateAnimation.setDuration(2000);
    mRotateAnimation.setRepeatCount(1);
    mRotateAnimation.setRepeatMode(Animation.REVERSE);

    上面代码含义为在2秒内将View旋转360度,再旋转回来,效果如下:

    二、Frame Animation

    看过电影的人也许知道,电影是由一张一张图片组成的,只不过图片切换速度快,在人视觉中看到的是连续效果。Frame Animation亦同样基于此原理实现,事先准备几张图片,按特定的顺序排好,然后使用特定的动画类将其播放,基于这种动画实现方式,Frame Anmation亦有一个中文名:逐帧动画。

    实现这种动画需要使用到AnimationDrawable类,它继承于Drawable,使用方式如下:

    private AnimationDrawable mAnimationDrawable;
    mAnimationDrawable = new AnimationDrawable();
    //增加图片,并设定图片播放时间
    mAnimationDrawable.addFrame(getResources().getDrawable(R.drawable.australia), 500);
    mAnimationDrawable.addFrame(getResources().getDrawable(R.drawable.austria), 500);
    mAnimationDrawable.addFrame(getResources().getDrawable(R.drawable.china), 500);
    mAnimationDrawable.start();

    上面代码是将三张图片按照指定的顺序,指定的时间播放,以达到动画效果,如下图:

    同样亦可以使用xml方式实现,代码如下:

    /anim/frame.xml

    <?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/australia" android:duration="500"/>
        <item android:drawable="@drawable/austria" android:duration="500"/>
        <item android:drawable="@drawable/china" android:duration="500"/>
    </animation-list>

    xml中调用:

    <ImageView
            android:id="@+id/frame_iv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@anim/frame"/>

    java中调用:

    private ImageView mFrameIv;
    private AnimationDrawable mAnimationDrawable;
    mFrameIv = (ImageView) findViewById(R.id.frame_iv);
    mAnimationDrawable = (AnimationDrawable) mFrameIv.getBackground();
    mAnimationDrawable.start();

    关于Frame Tween的知识比较简单,熟悉AnimationDrawable便行,下面介绍本章最重要的Property Animation。

    三、Property Animation

    中文亦叫属性动画,如其名字一样,可以改变对象的属性,注意是对象,不是View,而且是任意对象,只要对象符合一定条件即可,上述中的Tween Animation仅仅只能操作View,对于View之外的对象则无能为力,并且其未改变View的属性,仅仅是通过父类View对其重绘达到动画效果;而Frame Animation动画功能则过于简单。随着我们Android应用的发展,能发现Tween Animation、Frame Animation有时候并不能达到理想的效果,谷歌亦意识到了这点,故而在Android3.0之后增加了强大的属性动画。

    Property Animation有两个类可供使用:ValueAnimator、ObjectAnimator。这两个类均直接或间接继承于Animator

    ObjectAnimator使用方式如下:

    private ObjectAnimator mObjectAnimator;
    //设置不透明度从1到0变化
    mObjectAnimator = ObjectAnimator
                    .ofFloat(mObjectAnimatorIv, "alpha", 1, 0)
                    .setDuration(1000);
    //设置插值器,先加速后减速
    mObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
    //动画重复执行一次
    mObjectAnimator.setRepeatCount(1);
    //设置执行模式
    mObjectAnimator.setRepeatMode(ValueAnimator.REVERSE);
    mObjectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            //获取当前的动画值
            float cVal = (Float) animation.getAnimatedValue();
            //根据动画值缩放当前View
            mObjectAnimatorIv.setScaleX(cVal);
            mObjectAnimatorIv.setScaleY(cVal);
        }
    });

    上面代码意思是将当前View不透明度从1按照一定规律变为0,第一句代码中的ofFloat(mObjectAnimatorIv, "alpha", 1, 0)中的alpha代表不透明度,有人可能会说我可以写其他的吗?当然可以,比如写成ofFloat(mObjectAnimatorIv, "tmg", 1, 0),但你会发现动画执行后不会有效果,因为写这个字符串的前提是当前View或者当前View的父类中实现了这个字符串的get、set方法,即getAlpha、setAlpha,当动画执行时,动画类会通过调用setAlpha来改变View的alpha属性,达到想要的动画效果。那这个alpha是怎么从1便到0的呢?Property Animation中有一个TypeEvaluator,这个属性的含义是根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,上例中的alpha便是这样从1变到0的,但是上面并没设置TypeEvaluator啊?其原因是Property Animation

    会配置一个默认的TypeEvaluator,如果一定要显性设置,有几个写好的TypeEvaluator供选择:

    IntEvaluator:属性值的类型为int

    FloatEvaluator:属性值的类型为float

    ArgbEvaluator:属性的值类型为十六进制颜色值

    如果上述没有你需要的TypeEvaluator,你亦可以选择继承TypeEvaluator自定义一个类似的TypeEvaluator

    从上面代码中我们还可以看到:

    float cVal = (Float) animation.getAnimatedValue();
    mObjectAnimatorIv.setScaleX(cVal);
    mObjectAnimatorIv.setScaleY(cVal);

    其中animation.getAnimatedValue();是计算View当前属性值,当然根据前面的设置,这个属性值实在1到0之间变化,下面的两行代码是通过每个时刻不同的属性值对View进行缩放,达到在改变透明度的同时,

    又改变View大小的效果,效果图如下:

    同样的,Property Animation也可以通过xml实现,类似上面两种,不再介绍,读者可从之后分享的源码中看到

    ValueAnimator的使用方式和ObjectAnimator很相似,唯一的区别是ValueAnimator不能直接设置属性,即类似

    mObjectAnimator = ObjectAnimator
                    .ofFloat(mObjectAnimatorIv, "alpha", 1, 0)
                    .setDuration(1000);

    它只能这样:

    mValueAnimator = ValueAnimator.ofFloat(1, 0);
    mValueAnimator.setTarget(mValueAnimatorIv);

    动画效果可在监听事件中实现,如:

    mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float animatedValue = (float) animation.getAnimatedValue();
            mValueAnimatorIv.setAlpha(animatedValue);
            mValueAnimatorIv.setScaleX(animatedValue);
            mValueAnimatorIv.setScaleY(animatedValue);
        }
    });

    谈谈Keyframe,keyframe是一个时间/值对,通过它可以定义一个在特定时间的特定状态,

    即关键帧,而且在两个keyframe之间可以定义不同的Interpolator,就好像多个动画的拼接,第一个动画的结束点是第二个动画的开始。keyframe是抽象类,要通过ofInt(),ofFloat()等获得适当的keyframe,然后通过PropertyValuesHolder.ofKeyframe

    获得PropertyValuesHolder对象,如下例子:

    Keyframe kf0 = Keyframe.ofInt(0, 400);
    Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
    Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
    Keyframe kf3 = Keyframe.ofInt(0.75f, 100);
    Keyframe kf4 = Keyframe.ofInt(1f, 500);
    PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf3, kf4);
    mKeyframesObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(mKeyframesObjectAnimationBtn, propertyValuesHolder);
    mKeyframesObjectAnimator.setDuration(2000);
    mKeyframesObjectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            android.util.Log.d("update", (animation.getAnimatedValue()).toString());
        }
    });

    动画效果同样是在onAnimationUpdate中添加,上面仅仅是打个log

    如果你想应用多个动画,AnimationSet可以帮到你,AnimationSet提供了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序关系,如同时播放,顺序播放等。

    如下代码:

    mAnimatorSet = new AnimatorSet();
    mAnimatorSet.play(mObjectAnimator).before(mValueAnimator);
    mAnimatorSet.play(mValueAnimator).before(mKeyframesObjectAnimator);

    play是播放,before是在当前动画之前播放,还有2个方法with、after,分别是与当前动画同时播放,在当前动画之后播放,效果如下:

    上面是三个动画按照一定顺序播放,有时候我们需要比较复杂的动画效果时,这个类会很重要。

    四、扩展介绍

    interpolator:插值器,代表动画值的变化速度

    repeatCount:动画重复执行的次数

    repeatMode:动画执行模式,每次动画执行方式是一样还是按照相反方向执行

    duration:动画执行时间

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

    参考文章:

    http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html

    http://blog.csdn.net/lmj623565791/article/details/38092093

    源码:

    https://github.com/taothreeyears/animation

  • 相关阅读:
    Java.io.outputstream.PrintStream:打印流
    Codeforces 732F. Tourist Reform (Tarjan缩点)
    退役了
    POJ 3281 Dining (最大流)
    Light oj 1233
    Light oj 1125
    HDU 5521 Meeting (最短路)
    Light oj 1095
    Light oj 1044
    HDU 3549 Flow Problem (dinic模版 && isap模版)
  • 原文地址:https://www.cnblogs.com/tyrion/p/4335960.html
Copyright © 2011-2022 走看看