(一)快速开始
Animator是属性动画,通过修改对象的属性来达到实现动画的效果。
一段替换Animation全功能的Animator代码:(请使用3.0以上API来执行前面的例子)
ObjectAnimator animation = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
// ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 0, 500);
// ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationY", 0, 500);
// ObjectAnimator animation = ObjectAnimator.ofFloat(view, "scaleX", 0, 2f);
// ObjectAnimator animation = ObjectAnimator.ofFloat(view, "scaleY", 0, 2f);
// ObjectAnimator animation = ObjectAnimator.ofFloat(view, "rotation", 0, 360f);
// ObjectAnimator animation = ObjectAnimator.ofFloat(view, "rotationX", 0, 360f);
// ObjectAnimator animation = ObjectAnimator.ofFloat(view, "rotationY", 0, 360f);
animation.setDuration(5000);
animation.start();
以上代码可以实现:透明度,位移,缩放,旋转变化
Animatoin中包含的锚点,可以直接对view进行设置:
view.setPivotX(0);
view.setPivotY(0);
虽然属性动画不太适合用XML书写,但是其Java代码的属性难度非常低,很容易理解。
(二)总体脉络
首先从实现一个颜色渐变的动画开始,讲述属性动画的属性是指什么,然后讲述一下如何使用TypeEvaluator。
(三) 颜色的渐变动画
当你想改变一个View的背景颜色的时候,你想到的方法是什么?
view.setBackgroundColor(color);
而对于属性动画而言,你指定一个属性之后,动画框架会反射的去调用你的setXXX来实现对你的属性的修改。
根据这个思路,我们将属性命名为backgroundColor ,于是写下下面的代码:
ObjectAnimator animation = ObjectAnimator.ofInt(view, "backgroundColor",0xffffffff, 0xff00ff00);
animation.setDuration(5000);
animation.start();
然后,你会发现屏幕很魔性的闪个不停,从一种颜色到另一种颜色。也就是说,我们确实成功的改变了视图的背景颜色,只是颜色的期望和我们想的不太一致。
因为使用RGB作为一个int值的时候,你对颜色的改变会使得blue不断的从0变成255,所以出现的效果很差。
(四)TypeEvaluator
所以你可能希望讲int值拆分成不同的a,r,g,b维度,分别对其进行变换。这样就使得各个颜色进行了均匀的变换。
这个时候你可以考虑用TypeEvaluator,它对你的初始值和最终值做一个变换模型,然后计算中间某一个进度对应的值。
TypeEvaluator<Integer> colorTypeEvaluator = new TypeEvaluator<Integer>() {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int alpha = (int) (fraction * (Color.alpha(endValue) - Color.alpha(startValue)))
+ Color.alpha(startValue);
int red = (int) (fraction * (Color.red(endValue) - Color.red(startValue)))
+ Color.red(startValue);
int green = (int) (fraction * (Color.green(endValue) - Color.green(startValue)))
+ Color.green(startValue);
int blue = (int) (fraction * (Color.blue(endValue) - Color.blue(startValue)))
+ Color.blue(startValue);
return Color.argb(alpha, red, green, blue);
}
};
例如:
ObjectAnimator animation = ObjectAnimator.ofObject(view, "backgroundColor",
colorTypeEvaluator, 0xffffffff, 0xff00ff00);
的效果就是将颜色从白色慢慢的变成绿色,实现了我们的效果,非常的棒。
(五)颜色渐变的最终实现
但是,如果你想从红色变成绿色,并且中间颜色是过度的黄色。
ObjectAnimator animation = ObjectAnimator.ofObject(view, "backgroundColor",
colorTypeEvaluator, 0xffff0000, 0xff00ff00);
你会发现,在变换的过程中,并不会出现黄色,而是出现一种红不红绿不绿的奇怪颜色。
这是因为,你希望的是只是颜色色值发生变换,而饱和度和亮度都不要发生变化。
在这种情况下我们建议使用HSV颜色模型,而不是RGB颜色模型来进行过度。
【HSV请参考百度百科】
继续使用TypeEvaluator,同样只是对于值的映射有一些区别:
我们以HSV(colorStart)开始,以HSV(colorEnd)结束.
TypeEvaluator通过计算指定的开始数据与结束数据,然后得到中间的每一帧的数据。
TypeEvaluator<Integer> colorTypeEvaluator = new TypeEvaluator<Integer>() {
float[] hsvStart = null;
float[] hsvEnd = null;
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
if (hsvStart == null) {
hsvStart = new float[3];
Color.colorToHSV(startValue, hsvStart);
}
if (hsvEnd == null) {
hsvEnd = new float[3];
Color.colorToHSV(endValue, hsvEnd);
}
float[] returnHsv = new float[hsvStart.length];
for (int i = 0; i < hsvStart.length; i++) {
returnHsv[i] = hsvStart[i] + (hsvEnd[i] - hsvStart[i]) * fraction;
}
return Color.HSVToColor(returnHsv);
}
};
(六)再议属性动画
由于属性动画是对你的setXXX进行一个操作,所以,你可以考虑使用Wrapper的方式来实现多个值的同时修改。
Wrapper的动机是利用传入的参数的时机(set方法里),进行一些操作和处理,从而实现动画效果。
而它调用的方法是由你设置的属性("magic")和传入的类型(float)决定的。
static class Wrapper{
private View view;
public Wrapper(View view) {
this.view = view;
}
public void setMagic(float magic) {
view.setRotation(magic);
view.setRotationX(magic);
view.setRotationY(magic);
}
}
调用代码:
ObjectAnimator animation = ObjectAnimator.ofFloat(new Wrapper(view), "magic", 0, 360f);
这样就实现了超级翻转(X,Y,Z同时翻转)。
(七)包装器的替代方案:PropertyValuesHolder
使用Wrapper的好处很明显,可以同时改变多个值,但是PropertyValuesHolder告诉你, I CAN DO IT (我能干IT)
对于ObjectAnimator而言,它有一个使用 进行静态构造的方法。
public static ObjectAnimator ofPropertyValuesHolder(Object target,
PropertyValuesHolder... values) {
所以,我们需要构造PropertyValuesHolder对象。
PropertyValuesHolder有很多静态构造器,但是最简单好用的就是String propertyName那个.
例如,对于ofFloat而言:
public static PropertyValuesHolder ofFloat(String propertyName, float... values)
便可以构造一个PropertyValuesHolder对象。
如果我们想做一个同时scaleX和scaleY的动画,可以使用下面的实现:
PropertyValuesHolder holderX = PropertyValuesHolder.ofFloat("scaleX", 0f,1f);
PropertyValuesHolder holderY = PropertyValuesHolder.ofFloat("scaleY", 0f,1f);
ObjectAnimator animation = ObjectAnimator.ofPropertyValuesHolder(view, holderX, holderY);
animation.setDuration(5000);
animation.start();
它通过创建PropertyValuesHolder对象,然后将对象给需要修改的对象使用,动画框架将会修改对象的对于属性值。
对比Wrapper的这种方式,PropertyValuesHolder能够轻松的实现多值的同时修改,并且不需要改变目标对象。
(八)Wrapper方式与多对象
之前说的全是一个对象,假设是一组对象呢?
Wrapper立马大显身手,一下将问题解决了:
static class Wrapper {
private View[] views;
public Wrapper(View[] views) {
this.views = views;
}
public void setMagic(float magic) {
for (View view : views) {
view.setAlpha(magic);
}
}
}
(九)不指定target的ValueAnimator
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float alpha = (Float) (animation.getAnimatedValue());
view.setAlpha(alpha);
}
});
animation.setDuration(5000);
animation.start();
(十)AnimatorListener 与 AnimatorUpdateListener
当你希望在动画 [开始],[结束],[取消]或者[重复]的时候做一些事情,使用AnimatorListener。
animation.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
});