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

上一篇 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();
}

@Override
public 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();
            }
        });
    }

这里写图片描述

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值