ValueAnimator
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.start();
以上几句的意思就是做一个从0f到1f的平滑过渡,类似数字计时。因为没有和任何View联系在一起,所以不会有任何实际显示动画效果。
ObjectAnimator
ObjectAnimator继承自ValueAnimator
private void executeAnimation() {
float curTranslationX = mImageView.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(mImageView, "translationY", curTranslationX, 500f);
animator.setDuration(1000);
animator.start();
}
上面的代码意思是把这个ImageView 从它的当前位置Y轴向下移动。后面的参数可以多跟几个,如:
ObjectAnimator animator = ObjectAnimator.ofFloat(mImageView, "translationY", curTranslationX, 500f, 0f, 100f);
那么这里就是先向下移动500f,再移动回初始位置,再向下移动100f。
以上代码也可以使用ValueAnimator来完成:
float curTranslationX = mImageView.getTranslationX();
ValueAnimator anim = ValueAnimator.ofFloat(curTranslationX, 500f);
anim.setDuration(1000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationY((float)animation.getAnimatedValue());
}
});
anim.start();
可见,根据animation的value值来更新View的属性,达到动画效果。这里我们调用的是setTranslationY,也可以同时调用setTranslationX、setAlpha、setTop、setRoation等等。同时设置几个值,就会同时执行不同种类的动画。
利用AnimatorSet组合动画
这个就不说了,网上随便搜一下就有,示例代码:
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();
使用TypeEvaluator
通过定义TypeEvaluator可以自己定义动画的执行方式
private void executeAnimation() {
float curTranslationY = mImageView.getTranslationY();
ValueAnimator anim = ValueAnimator.ofObject(new MyTypeEvaluator(), curTranslationY, 100.0f);
anim.setDuration(1000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationY((float) animation.getAnimatedValue());
}
});
anim.start();
}
class MyTypeEvaluator implements TypeEvaluator<Float> {
@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
float startFloat = startValue.floatValue();
return startFloat + 0.5f * (fraction * fraction) *(9.8f) * (endValue.floatValue() - startFloat);
}
}
以上,模拟一个自由落体动画。自定义类里面的fraction表示动画执行的进度,配合这个进度,用公式表达出一个自由落体(公式是瞎JB写的)。这个返回值就是动画执行过程中不停更新的value值。我们通过设置监听,实时通过setTranslationY更新view的位置。
注意,evaluate方法的返回值是一个Object,这里我利用泛型规定为float,这个返回可以是任意对象。比如某些例子里面返回的是一个point对象,其中可以携带x和y两个位置信息。那么我们在ValueAnimator.ofObject里面传入的参数也应该是两个point,代表动画执行过程中,这个point从point1渐渐变成了point2。如:
Point point1 = new Point(0, 0);
Point point2 = new Point(300, 300);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);
anim.setDuration(5000);
anim.start();
使用ViewPropertyAnimator
直接对某个View调用animate()。返回一个ViewPropertyAnimator对象。然后在对这个对象进行操作,示例:
imageView.animate().scaleX(30.0f).scaleY(30.0f).setDuration(300).start();
这句的意思是对该view进行放大操作。一连串的调用,每次返回的还是ViewPropertyAnimator对象。这个不知道是不是在使用装饰模式?可以研究一下源码判断。
总结:
我在使用属性动画的过程中,觉得还是不能方便的、随心所欲的控制。有时候不得不创建好几个动画,在A执行完后(使用监听器监听结束),再去开启另一段动画。代码上非常冗长,可读性较差。后面需要继续探究其灵活简便的用法。