动画介绍:
- 在Android动画中,总共有两种类型的动画View Animation(视图动画)和Property Animator(属性动画);
- View Animation包括Tween Animation(补间动画)和Frame Animation(逐帧动画);
Property Animator包括ValueAnimator和ObjectAnimation;
区别:
- View Animation仅能对指定的控件做动画,而Property Animator是通过改变控件某一属性值来做动画的。
- 补间动画虽能对控件做动画,但并没有改变控件内部的属性值。而Property Animator则是恰恰相反,Property Animator是通过改变控件内部的属性值来达到动画效果的。
属性动画:
ValueAnimator
- 注意:单从名字上就可以看出来,这个Animator是针对数值进行操作的,不对控件做操作。控件和它并没有什么关系,重点在数值上的操作。
- 两点:
- ValueAnimator只负责对指定数值区间,进行运算。
- 自己需要对运算进行监听,然后自己对控件进行操作。
ValueAnimator animator = ValueAnimator.ofInt(0,400);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//拿到监听结果,自己处理。
int curValue = (int)animation.getAnimatedValue();
tvTextView.layout(curValue,curValue,curValue+tv.getWidth(),curValue+tv.getHeight());
}
});
animator.start();
常用方法和监听:
- 方法:和Animation差不多,看文档。
- 监听:
- AnimatorUpdateListener:监听动画变化时的实时值。addUpdateListener(AnimatorUpdateListener listener)。
- AnimatorListener:监听动画变化时四个状态。addListener(AnimatorListener listener)。
- 移除监听:
/**
* 移除AnimatorUpdateListener
*/
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
/**
* 移除AnimatorListener
*/
void removeListener(AnimatorListener listener);
void removeAllListeners();
查看这段代码:
ValueAnimator animator = ValueAnimator.ofInt(0,600);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
}
});
animator.setInterpolator(new LinearInterpolator());
animator.start();
上面代码中,在1000毫秒的时间中,ValueAnimator的功能是,使数值从0到600根据插值器的类型去变化。 (int)animation.getAnimatedValue()得到的是0~600之间的值,这个数值的获取是Interpolator和Evalutor作用的结果。
- 0~600得到的值是否是匀速变化还是其他速度变化的,由Interpolator决定。
- animation.getAnimatedValue()得到的值是多少,什么类型由Evalutor决定。
inInt(0,600) | 加速器 | 估值器 | 监听器返回 |
---|---|---|---|
设置数值区间 | Interpolator动画比例 | 根据加速器的动画比例算出实际值 | getAnimatedValue得到实际值 |
插值器/加速器 Interpolator
- 默认每10毫秒刷新一次
//线性加速器
public class LinearInterpolator implements Interpolator {
public LinearInterpolator() {}
public LinearInterpolator(Context context, AttributeSet attrs) {}
public float getInterpolation(float input) {
return input;
}
}
public interface Interpolator extends TimeInterpolator {}
参数input:是一个float类型,它取值范围是0到1,表示当前动画的进度,取0时表示动画刚开始,取1时表示动画结束,取0.5时表示动画中间的位置,其它类推。
返回值:表示当前实际想要显示的进度。取值可以超过1也可以小于0,超过1表示已经超过目标值,小于0表示小于开始位置。
再重复一遍,input参数与任何我们设定的值没关系,只与时间有关,随着时间的增长,动画的进度也自然的增加,input参数就代表了当前动画的进度。而返回值则表示自定义后的动画的当前数值进度。
上面代码:为什么LinearInterpolator是线性匀速变化的呢?
因为插值器根据设置的总时间,每10ms刷新一次,调用getInterpolation传入当前的进度,LinearInterpolator中原值返回了,没有改变默认进度。
看自定义加速器代码对比:
public class MyInterpolator implements Interpolator {
/**
* input 是实际动画执行的时间比例 0~1
* newInput 你想让动画已经执行的比例 0~1。
* 注意:都是比例,而不是实际的值。
*
* setDuration(1000)情况下:前200ms走了3/4的路程比例,后800ms走了1/4的路程比例。
* 注意:这里输出的是比例,是路程比例,不是实际的路程值!
*/
@Override
public float getInterpolation(float input) {
if (input <= 0.2) {//后1/4的时间,输出3/4的比例
float newInput = input*4;
return newInput;
}else {//后3/4的时间,输出1/4的比例
float newInput = (float) (input - 0.2)/4 + 0.8f;
return newInput;
}
}
}
Evaluator 估值器
我们通过加速器得到的是动画进度的比例,并不是实际的数值,Evaluator就是转换成实际值的地方。(ofInt(0,600)中加速器拿到的是动画的比例值,估值器根据比例转换成实际的值。AnimatorUpdateListener监听器中拿到的实际数值,就是通过Evaluator转换后的值。)
- 看下面系统Evaluator代码:
//设置取值区间时setIntValues(0,600)/setFloatValues(0,600),这是系统方法,会自动为我们设置相应的类型的Evaluator。
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
//fraction是在插值器中处理后的进度,在这里以此转换成实际值。
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
- 开下面自定义Evaluator代码:
public class PointEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
int radius = (int) (startValue.getRadius() + fraction*(endValue.getRadius() - startValue.getRadius()));
return new Point(radius);
}
}
public void doAnimation(){
//ValueAnimator animatior = ValueAnimator.ofObject(new PointEvaluator(), new Point(20), new Point(80));
//上下作用一样,不可混用。
ValueAnimator animatior = new ValueAnimator();
animatior.setObjectValues(new Point(20), new Point(80));
animatior.setEvaluator(new PointEvaluator());
animatior.setDuration(2000);
animatior.setInterpolator(new BounceInterpolator());
animatior.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
animatior.start();
}
关于取值范围
- void setObjectValues(Object... values);
- void setIntValues(int... values);
- void setFloatValues(float... values);
animatior.setObjectValues(new Point(20), new Point(150),new Point(80), new Point(200), new Point(20), new Point(150));
animatior.setDuration(2000);
public class PointEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
int radius = (int) (startValue.getRadius() + fraction*(endValue.getRadius() - startValue.getRadius()));
return new Point(radius);
}
}
看上面的代码可以发现,setObjetValue可以有n个值。但是Evaluator估值器中只有startValue和endValue。
26.698 evaluate: startPoint=20-endPoint=150-fraction=0.0
......
26.979 evaluate: startPoint=20-endPoint=150-fraction=0.994
26.995 evaluate: startPoint=150-endPoint=80-fraction=0.049999993
27.245 evaluate: startPoint=150-endPoint=80-fraction=0.92499995
27.262 evaluate: startPoint=150-endPoint=80-fraction=0.9844998
27.278 evaluate: startPoint=80-endPoint=200-fraction=0.043999884
......
27.546 evaluate: startPoint=80-endPoint=200-fraction=0.975
27.562 evaluate: startPoint=200-endPoint=20-fraction=0.03449991
......
27.828 evaluate: startPoint=200-endPoint=20-fraction=0.9689996
27.847 evaluate: startPoint=20-endPoint=150-fraction=0.02499974
......
28.112 evaluate: startPoint=20-endPoint=150-fraction=0.9595001
28.129 evaluate: startPoint=150-endPoint=80-fraction=0.018999936
......
28.179 evaluate: startPoint=150-endPoint=80-fraction=0.99399978
ke以发现,设置取值范围的时候,有几个参数,就把setDuration(2000)的时间分为多少分,1&2/2&3 / 3&4...作为start/endValue。至于每份取得的时间比例,就看设置的插值器了。
tips
- ArgbEvalutor 颜色估值器。