上一篇 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();
}
});
}
源码下载