属性动画(Property Animation)是Android 3.0出现的动画,它将动画逻辑从view中抽离了出来,抽象化程度更高。上一篇讲的是补间动画,其动画渲染是实际的位置是不变的,就像幻影一样,而属性动画是真实的位置改变。看名字我们就可以猜测它是对view的属性(x,y,alpha等)进行改变从而实现动画。属性动画主要包括两个关键类:ValueAnimator和ObjectAnimator。
ValueAnimator通过ValueAnimator.ofFloat(float …value)进行构造,可以有多个参数。动画的运行就是按照参数的变化而变化,中间值使用插值器插值(Interpolator),构造后还可以设置其他属性,例如:
ValueAnimator an = ValueAnimator.ofFloat(0,360);
an.setDuration(2000);
an.setRepeatCount(ValueAnimator.INFINITE);//或-1,一直循环
an.setRepeatMode(ValueAnimator.RESTART);
an.setInterpolator(new LinearInterpolator());
an.start();
将ValueAnimator设置构造完成后,就需要监听里面数字的变化的,给ValueAnimator加入dUpdateListener监听器
an.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
/*这里可以做你想做的事,如setROtation,setAlpha等,只要view有set<属性>的方法都可以,另外我们还可以在view自定义set方法。*/
view.setRotation((Float)animation.getAnimatedValue());
}
});
通过监听ValueAnimator的值变化,控制view的属性变化(如:setRotation()),这样就实现了动画的操作了。
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:interpolator="@android:anim/linear_interpolator"
android:repeatCount="-1"
android:repeatMode="reverse"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" >
animator>
读取xml资源定义的动画
ValueAnimator an = (ValueAnimator) AnimatorInflater.loadAnimator(this,R.anim.value_animation);
an.start();
an.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.d("tag", "值:"+(Float)animation.getAnimatedValue());
}
});
ValueAnimator还可以使用ofObject(evaluator, values)的构造方法,此时就需要实现TypeEvaluator接口了。
这个接口了可以实现除了系统提供的类型如float(开始时我们就是使用float构造)之外的类型的变化。类似于c++的重载运算符。例如定义person A怎么变成person B的。我们先看看之前使用的offFloat构造时使用的TypeEvaluator是怎么样的。下面是android源码。
public class FloatEvaluator implements TypeEvaluator<Number> {
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}
可以看到float类型的变换是startFloat + fraction * (endValue - startFloat);fraction为动画进行的百分比。现在我们来定义person A变成person B,我们就假设A变老了就成B了,即年龄变化即可。实现如下:
public class PersonEvaluator implements TypeEvaluator<Person>{
@Override
public Person evaluate(float fraction, Person startValue, Person endValue) {
int startAge = startValue.getAge();
Person p = new Person(startValue);
int r = (int) (startAge+fraction*(endValue.getAge()-startAge));
p.setAge(r);
return p;
}
}
这样我们就可以使用offOject的构造方法了,这时候UpdateListener回调AnimatedValue就是一个person了。
Person A = new Person(11);
Person B = new Person(22);
ValueAnimator personAnim = ValueAnimator.ofObject(new PersonEvaluator(), A,B);
personAnim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Person p = (Person) animation.getAnimatedValue();
Log.d("tag", "年龄:"+p.getAge());
}
});
如果将Person变成是图片,那不就是成了帧动画了吗?具体用途还是看各位想象了。
这个是用起来最方便的动画了,我觉得。
//透明度1-0变化的动画
tvhello = (TextView) findViewById(R.id.hello);
tvhello.animate().alpha(1).alpha(0).setDuration(2000);
一行代码搞掂。(不过这种需要android 3.1以上才能使用)
ObjectAnimator是继承于ValueAnimator的类,因此上面介绍valueAnimator有的东西它都有,比如TypeEvaluator的自定义。它主要实现的是查找传出对象的setter方法,在UpdateListener上调用,这样我们就不需要自己去监听UpdateListener了。
tvhello = (TextView) findViewById(R.id.hello);
ObjectAnimator anim0 = ObjectAnimator.ofFloat(tvhello, "alpha", 1f,0f,1f);
anim0.start();
也很简单,两行搞掂。这里实现的是透明度从1f->0f—>1f;”alpha”对应于view中的setAlpha 方法。其他的例如setTranslationX就写成”translationX”。只有有setter方法都可以用。(即使没有setter的方法我们也可以自定
义view加上哦,满足驼峰式命名就行)。
ObjectAnimator中输出TypeEvaluator参数。这里写的是颜色的变化,Person换成了点poin.
//[自定义view参数] poin,这里自定义view需要定义setPoin(Poin p);方法。
ObjectAnimator an = ObjectAnimator.ofObject(myview, "poin",new ColorEvalutor(),new Poin(),new Poin());
使用PropertyValuesHolder实现多个属性一起变化。
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 0f,1f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("rotetion", 1f,180f);
//holder的个数不限
ObjectAnimator.ofPropertyValuesHolder(tvhello, holder1,holder2).setDuration(2000).start();
定义多个ObjectAnimator,然后使用AnimatorSet串起来。
ObjectAnimator anim0 = ObjectAnimator.ofFloat(tvhello, "alpha", 1f,0f,1f);
ObjectAnimator anim1 = ObjectAnimator.ofFloat(tvhello, "translationX", tvhello.getTranslationX(),-500,100);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(tvhello, "rotation", 0,180,0);
AnimatorSet animset = new AnimatorSet();
animset.play(anim0).after(anim1).with(anim2);
animset.setDuration(2000);
animset.start();
AnimatorSet使用的是建造者模式,animset.play(anim0)返回一个build,然后就可以设置我们的组合动画了。也可以这样写
animset.play(anim0).with(anim1)
animset.play(anim1).before(anim2)
animset.play(anim3).after(anim2)
此时是anim0和anim1一起播放,anim2在anim1播放之后播放,anim3在anim2播放之后播放。可能比较难理解。这就像我们平时排队一样,谁在谁左边一样,注意不能前后矛盾哦。给这动画排队就是 [(anim0,anim1)、anim2、anim3] 你再对照一下是不是满足了。还有解析一下animset.play(anim0).after(anim1).with(anim2);这都是以anim0为基准进行描述的,排队循序:anim1、(anim0,anim2).
对xml构造ValueAnimator扩展到所有属性动画。
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially" >
<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="5"
android:valueType="floatType" />
<set android:ordering="together" >
<objectAnimator
android:duration="1000"
android:propertyName="rotationX"
android:valueFrom="10"
android:valueTo="1"
android:valueType="floatType" />
<objectAnimator
android:duration="1000"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="0.5"
android:valueType="floatType" />
set>
set>
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.set_simple);
anim.setInterpolator(new DecelerateInterpolator(2f));//设置变化规律,如:先快后慢。可自定义
anim.setTarget(tvhello);
anim.start();
属性动画有一个AnimatorListener接口,而如果我们只需要监听部分事件,只需要使用它的实现类AnimatorListenerAdapter,然后重写相关方法就行了。
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
Log.d("tag", "动画结束了");
}
});
Interpolator是补间动画上就有的,而属性动画在此基础上加了TimeInterpolator,它可以控制动画的速率(先快后慢,加快,变慢等)上一篇有介绍:Android动画的使用(一):补间动画与逐帧动画,这里主要讲如何写自己的插值器Interpolator
public interface TimeInterpolator {
float getInterpolation(float input);
}
只有一个方法,这样我们就可以实现自己的插值器了。
先看使用Android提供的插值器
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.set_simple);//xml定义的属性动画
anim.setInterpolator(new DecelerateInterpolator(2f));//设置变化规律,如:先快后慢。可自定义
直接setInterpolator就可以使用了。OK,我们来实现自己的插值器。
public class MyInterpolator implements TimeInterpolator{
@Override
public float getInterpolation(float input) {
//input是时间百分比,取值范围是(0-1)
//return input;匀速就是直接返回了。
return input*input;
}
}
我们直接平方,这就是二次函数,0-1之间就是开始是慢后面加快了。
//使用自己的插值器
anim.setInterpolator(new MyInterpolator());