Android 属性动画浅谈(二)基础运用及工作原理

来源:互联网 发布:杭州网络推广hzzdsem 编辑:程序博客网 时间:2024/05/01 05:22

上一篇 Android 属性动画浅谈(一)插值器和估值器
我们主要讲了插值器和估值器的源码分析、具体使用以及自定义一个插值器和估值器。

当然了属性动画还有一部分的知识点,就是属性动画的基础,本来打算先第一篇先写属性动画的基础运用,第二篇在写插值器和估值器的。正好那天同事问了我这方面的知识,就顺手写了!不过,属性动画的基础运用将在本篇博客为大家展示~

由于Android3.0之前已有的动画框架Animation存在一些局限性—动画改变的只是显示,并不能响应事件。因此,在Android3.0之后。Google就提出了属性动画这一新的动画框架。那么大家是不是存在疑问3.0之前的怎么使用属性动画呢?好在开源大神们已经帮我们解决这个问题了。NineOldAndroids这个项目。:属性动画兼容库。https://github.com/JakeWharton/NineOldAndroids 作者:JakeWharton。其实,我们平常使用的注解工具butterknife也是他开发的。https://github.com/JakeWharton这是他的github地址。好了,不多说。我们来介绍下NineOldAndroids吧!

NineOldAndroids将Honeycomb animation API 移植到了整个Android Version平台,使得ValueAnimator、ObjectAnimator等Honeycomb animation API 能不改一行代码,只修改import的包名就完全兼容到新的api。
使用:
如果你熟悉Honeycomb animation API 的话,那么使用就非常简单了,只需要将import android.animation.ObjectAnimator替换为 com.nineoldandroids.animation.ObjectAnimator 即可。

Animator框架中使用最多的就是Animator和ObjectAnimator配合,使用ObjectAnimator 进行更精细化控制,只控制一个对象的一个属性值,而使用多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动。可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画中多次绘制界面,而在不影响动画效果的前提下减少CPU资源消耗。最重要的是,属性动画通过调用属性的get,set方法来真实地控制了一个View的属性值,因此,强大的属性动画框架,基本可以实现所有的动画效果。

一、ObjectAnimator

ObjectAnimator 是属性动画框架中最重要的实行类。创建一个ObjectAnimator对象只需要静态工厂类直接返回一个ObjectAnimator对象。参数包括一个对象和对象的属性名字,注意:这个属性必须有set和get方法。因为,其内部是通过java反射机制来调用set函数修改对象属性值。下面我们来写一下:

ObjectAnimator   animator=ObjectAnimator.ofFloat(view,"translationX",300);animator.setDuration(300);animator.start();

可以看到,通过ObjectAnimotor的静态工厂方法,创建一个ObjectAnimator对象,第一个参数是实现动画的View,第二个参数是该View的属性,最后一个参数是一个可变数组参数,这里只设置一个参数,即变化到300.当然,也开始给属性动画设置时长,插值器等属性。这里需要注意的是:操纵的属性必须具有set、get函数。
那么问题来了,如果,该属性没有set、get方法呢。不用着急,Google已经为我们解决了这个问题。Google在应用层提供了2种解决方案。一个是通过自定义一个属性类或者包装类,来间接的给这个属性增加get、set方法;或者通过ValueAnimator来实现。ValueAnimator我们会在后面讲。这里先来看看如何使用包装类实现增加set、get方法的。代码:

pirvate static class AnimatorTestView{    private View mView;    public AnimatorTestView(View view){    view=mView;    }    public void int getHeight(){    return mView.getLayoytParams().height;    }    public void setHeight(int height){    mView.getLayoytParams.height=height;    mView.requertLayout();    }}

通过以上代码,就给一个属性包装了一层,并给它提供了set、get方法。使用时只需要操纵包装类就可以间接调用到get、set方法了。使用:

AnimatorTestView testView=new AnimatorTestView(imageView); textView.ofInt(testView,"height",100).setDuration(1000).start();

二、ValueAnimator

ValueAnimator 在属性动画中占有非常重要的地位,虽然不像ObjectAnimtor那样耀眼,但是它是属性动画的核心,ObjectAnimator继承自ValueAnimator。

 public void class ObjectAnimator extends ValueAnimator

ValueAnimator 本身不提供任何动画效果,不作用于任何对象,它更想一个数值发生器也就是说直接使用它没有任何动画效果。它可以对一个值做动画,然后我们可以监听其动画过程,在动画过程中修改我们的对象的属性值,这样也就相当于我们的对象做了动画。还是不太明白?没关系,下面用例子说明

private void performAnimate(final View view, final int start, final int end) {    ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);    valueAnimator.addUpdateListener(new AnimatorUpdateListener() {       //持有一个IntEvaluator对象,方便下面估值的时候使用        private IntEvaluator mEvaluator = new IntEvaluator();        @Override        public void onAnimationUpdate(ValueAnimator animator) {            //获得当前动画的进度值,整型,1-100之间            int currentValue = (Integer)animator.getAnimatedValue();            Log.e("MA", current value:  + currentValue);            //计算当前进度占整个动画过程的比例,浮点型,0-1之间            float fraction = currentValue / 100f;            //直接调用整型估值器通过比例计算出高度,然后再设给ImageView            view.getLayoutParams().height = mEvaluator.evaluate(fraction, start, end);            view.requestLayout();        }    });    valueAnimator.setDuration(5000).start();}@Overridepublic void onClick(View v) {    if (v == imageView) {        performAnimate(imageView, imageView.getHeight(), 1000);    }}

三、AnimatorSet

对于一个属性实现多个动画效果,View动画里面是AnimationSet类。在属性动画里面则是AnimatorSet类。AnimatorSet不仅能实现多个动画效果,还能实现更为精确的顺序控制。使用:

ObjectAnimator animator1=new ObjectAnimator(view,"translationX",100);ObjectAnimator animator2=new ObjectAnimator(view,"scaleX",1f,0f,1f);ObjectAnimator animator3=new ObjectAnimator(view,"scaleY",1f,0f,1f);ObjectAnimator animator4=new ObjectAnimator(view,"translationY",100);AnimatorSet set=new AnimatorSet();set.setDuration(5000);//set.playTogether(animator1,animator2,animator3,animator4);set.play(animator2).with(animator3).after(animator1);

在属性动画中,AnimatorSet正是通过
playTogether(),playSequentially(),animSet.play().with(),before(),adter()这些方法来控制多个动画协同工作。从而实现顺序控制。

四、动画事件的监听

一个完整的动画是有 Start,Repeat,End,Cancel四个过程。通过Android提供的接口,可以很方面的监听到这四个事件。代码如下:

ObjectAnimator object= ObjectAnimator.ofFloat(pb_img,"scaleX",1f,0f,1f);        object.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {            }            @Override            public void onAnimationCancel(Animator animation) {            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });

不过,我们大部分只关注onAnimationEnd事件,所以Android也提供了AnimatorListenerAdapter来让我们选择需要的事件来监听。代码如下:

object.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);            }        });

当然,属性动画和View动画一样。也可以直接写在XML文件中,这里我就不多做介绍了。其用法和View动画类似。

五、属性动画工作原理

属性动画要求动画作用的对象提供该属性的set方法,属性动画根据你传递的该属性的初始值和最终值,以动画的效果多次去调用set方法。每次传递给set方法的值都是不一样的确切来说是随着时间的推移,所传递的值越来越接近最终值。如果动画的时候没有传递初始值,那么还要提供get方法,因为系统要去获取属性的初始值。对于属性动画来说,其动画过程中所做的就是这么多。

public void animator(){        //alpha rotation translationX scaleY        ObjectAnimator animAlpha=ObjectAnimator.ofFloat(img,"alpha",1f,0f,1f);        ObjectAnimator animRotation=ObjectAnimator.ofFloat(img,"rotation",0f,360f);        ObjectAnimator animTranslation=ObjectAnimator.ofFloat(img,"translationX",0f,500f,0f);        ObjectAnimator animSacle=ObjectAnimator.ofFloat(img,"scaleY",1f,3f,1f);        //组合动画        AnimatorSet anim=new AnimatorSet();        anim.setDuration(3000);        anim.play(animAlpha).with(animRotation).with(animSacle).after(animTranslation);        anim.setInterpolator(new AccelerateDecelerateInterpolator());//差之器        anim.start();        //Animator监听器--AnimatorListener--AnimatorListenerAdapter        anim.addListener(new AnimatorListenerAdapter() {            @Override            public void onAnimationEnd(Animator animation) {                super.onAnimationEnd(animation);                Toast.makeText(ProperAnimationActivity.this,"动画结束",Toast.LENGTH_SHORT).show();            }        });    }

这里写图片描述

源码下载

2 0