注意:本篇文章是本人阅读关于Android动画的文章所写下的总结,方便以后查阅,所有内容非原创,侵权删。
本篇文章内容来自于
- Android高级进阶 顾浩鑫
- Android自定义控件三部曲文章索引之动画篇
目录
4.属性动画PropertyAnimation(基类Animator)
--4.1 ValueAnimator
----4.1.1 ValueAnimator构造函数
----4.1.2 ValueAnimator常用方法
----4.1.3 ValueAnimator监听器(2种)
----4.1.4 ValueAnimator代码实现(5种)【3和5待补】
----4.1.5 首先理解interpolator和Evaluator的功能和关系
----4.1.6 interpolator插值器(系统+自定义)
----4.1.7 Evaluator(系统+自定义)
----4.1.8 ValueAnimator XML实现
4.属性动画PropertyAnimation(基类Animator)
一个完整的属性动画由两部分组成:
1.计算动画各个帧的相关属性值
2.将这些属性值设置给指定的对象
4.1 ValueAnimator(属性动画最重要的类)
ValueAnimator只实现了属性动画应该具备的两个功能的第一个,第二部分由开发者自行设置。
即ValueAnimator不会对控件做任何操作,我们可以给它设定从哪个值运动到哪个值,通过监听这些值的渐变过程来自己操作控件。
4.1.1 ValueAnimator构造函数
ValueAnimator的构造函数是空实现,一般使用静态工厂方法来实现实例化。
public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofArgb(int... values)
public static ValueAnimator ofFloat(float... values)
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)
参数类型都是可变参数长参数,所以我们可以传入任何数量的值;
传进去的值列表,就表示动画时的变化范围;
比如ofInt(2,90,45)就表示从数值2变化到数字90再变化到数字45;
4.1.2 ValueAnimator常用方法
//设置动画时长,单位是毫秒
ValueAnimator setDuration(long duration)
//获取ValueAnimator在运动时,当前运动点的值
Object getAnimatedValue();
//开始动画
void start()
//设置循环次数,设置为0表示不循环,设置为ValueAnimation.INFINITE表示无限循环。
void setRepeatCount(int value)
//设置循环模式
//取值为ValueAnimation.RESTART时,表示正序重新开始,当取值为ValueAnimation.REVERSE表示倒序重新开始。
void setRepeatMode(int value)
//设置插值器
setInterpolator(xxxx)
//取消动画
void cancel()
// 延时多久时间开始,单位是毫秒
public void setStartDelay(long startDelay)
//完全克隆一个ValueAnimator实例,包括它所有的设置以及所有对监听器代码的处理
public ValueAnimator clone()
4.1.3 ValueAnimator监听器(2种)
监听器一:监听动画变化时的实时值
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
//添加方法
public void addUpdateListener(AnimatorUpdateListener listener)
//移除方法
public void removeUpdateListener(AnimatorUpdateListener listener);
public void removeAllUpdateListeners();
//===代码实现===
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());
}
});
监听器二:监听动画变化时四个状态
public static interface AnimatorListener {
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}
//添加方法
public void addListener(AnimatorListener listener)
//移除方法
void removeListener(AnimatorListener listener);
void removeAllListeners();
//===代码实现===
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.d("xl","animation start");
}
@Override
public void onAnimationEnd(Animator animation) {
Log.d("xl","animation end");
}
@Override
public void onAnimationCancel(Animator animation) {
Log.d("xl","animation cancel");
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.d("xl","animation repeat");
}
});
4.1.4 ValueAnimator代码实现(5种)
1⃣️ ofInt(只能传入Integer类型的值)
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 400);
valueAnimatorInt.setDuration(1000);
valueAnimatorInt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int) animation.getAnimatedValue();
tvAnimPropertyValue.layout(curValue,curValue,curValue+tvAnimPropertyValue.getWidth(),curValue+tvAnimPropertyValue.getHeight());
}
});
valueAnimatorInt.start();
2⃣️ ofFloat(只能传入Float类型的值)
ValueAnimator valueAnimatorFloat = ValueAnimator.ofFloat(0f, 400f, 50f, 300f);
valueAnimatorFloat.setDuration(3000);
valueAnimatorFloat.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
int curValue = (int) animatedValue;
tvAnimPropertyValue.layout(curValue,curValue,curValue+tvAnimPropertyValue.getWidth(),curValue+tvAnimPropertyValue.getHeight());
}
});
valueAnimatorFloat.start();
3⃣️ ofArgb
4⃣️ ofObject(可以传进去任何类型的变量)
构造方法解释
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values);
/*两个参数,第一个是自定义的Evaluator,第二个是可变长参数,Object类型的;
为什么要强制传进去自定义的Evaluator?
Evaluator的作用是根据当前动画的显示进度,计算出当前进度下把对应的值。
既然Object对象是我们自定的,那必然从进度到值的转换过程也必须由我们来做,不然系统不知道要转成什么鬼。*/
实例
ValueAnimator valueAnimatorObject = ValueAnimator.ofObject(new CharEvaluator(), new Character('A'), new Character('Z'));
valueAnimatorObject.setDuration(10000);
valueAnimatorObject.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
char animatedValue = (char) animation.getAnimatedValue();
tvAnimPropertyValue.setText(String.valueOf(animatedValue));
}
});
valueAnimatorObject.start();
public class CharEvaluator implements TypeEvaluator<Character> {
@Override
public Character evaluate(float fraction, Character startValue, Character endValue) {
int startInt = (int)startValue;
int endInt = (int)endValue;
int curInt = (int)(startInt + fraction *(endInt - startInt));
char result = (char) curInt;
return result;
}
}
5⃣️ ofPropertyValuesHolder
参考ObjectAnimator的ofPropertyValuesHolder的实现
4.1.5 首先理解interpolator和Evaluator的功能和关系
ValueAnimator anim = ValueAnimator.ofInt(100, 400);
anim.setDuration(1000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
Log.d("TAG", "cuurent value is " + currentValue);
}
});
anim.start();
在添加了AnimatorUpdateListener的监听以后,通过在监听函数中调用 animation.getAnimatedValue()就可以得到当前的值;
那当前的值是怎么来的呢?
当前的值 = 100 + (400 - 100)* 显示进度
- 100和400就是我们设置的ofInt(100,400)中的值
- 显示进度是通过interpolator得到 [interpolator将时间变化(0-1)转化成显示进度(0-1,但也可以大于1小于0)]
- 而整个公式当前的值 = 100 + (400 - 100)* 显示进度是在Evaluator中计算的。
关系图如下
4.1.6 interpolator插值器
插值器用来将时间进度转换成显示进度
1.系统自带插值器
意义如下:
AccelerateDecelerateInterpolator 在动画开始与介绍的地方速率改变比较慢,在中间的时候加速
AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速
AnticipateInterpolator 开始的时候向后然后向前甩
AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值
BounceInterpolator 动画结束的时候弹起
CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator 在动画开始的地方快然后慢
LinearInterpolator 以常量速率改变
OvershootInterpolator 向前甩一定值后再回到原来位置
使用
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setInterpolator(new BounceInterpolator());
....
2.自定义插值器
先看看系统加速器LinearInterpolator的写法:
//以常量速率改变的加速器LinearInterpolator
public class LinearInterpolator implements Interpolator {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
}
//接口Interpolator(LinearInterpolator实现了Interpolator接口)
public interface Interpolator extends TimeInterpolator {
}
//(Interpolator接口则直接继承自TimeInterpolator)
public interface TimeInterpolator {
float getInterpolation(float input);
/*
参数input:
input参数是一个float类型,它取值范围是0到1,表示当前动画的时间进度(与我们的任何设置无关).
取0时表示动画刚开始,取1时表示动画结束,取0.5时表示动画中间的位置,其它类推。
返回值:
表示当前实际想要显示的进度。取值可以超过1也可以小于0。
超过1表示已经超过目标值,小于0表示小于开始位置。
*/
}
从上面可以看到,LinearInterpolator在getInterpolation函数中,直接把input值返回,即以当前动画的进度做为动画的数值进度,这也就表示当前动画的数值进度与动画的时间进度一致,比如,如果当前动画进度为0,那动画的数值进度也是0,那如果动画进度为0.5,那动画的数值进度也是在0.5,当动画结束,动画的进度就变成1了,而动画的数值进度也是1了。
则自定义Interpolator
public class MyInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
return 1-input;
}
}
使用
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setInterpolator(new MyInterpolator());
...
4.1.7 Evaluator
Evaluator是根据加速器返回的小数进度转换成当前数值进度所对应的值。
1.系统自带Evaluator
Evaluator是专用的。
Evalutor一般来讲不能通用,会报强转错误,也就是说,只有在数值类型相同的情况下,Evalutor才能共用。
ofInt()对应的Evaluator类名叫IntEvaluator
ofFloat()对应的Evaluator类名叫FloatEvaluator
ofInt和ofFloat都是系统直接提供的函数,所以在使用时都会有默认的加速器和Evaluator来使用的,不指定则使用默认的;
ArgbEvalutor是用来做颜色值过渡转换的。可配合使用ofInt()
ValueAnimator valueAnimatorIntArgb = ValueAnimator.ofInt(0xffffff00, 0xff0000ff);
valueAnimatorIntArgb.setDuration(3000);
valueAnimatorIntArgb.setEvaluator(new ArgbEvaluator());
valueAnimatorIntArgb.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
tvAnimPropertyValue.setBackgroundColor(curValue);
}
});
valueAnimatorIntArgb.start();
2.自定义Evaluator
看看IntEvaluator内部是怎么实现:
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
/*
其中fraction就是加速器中的返回值,表示当前动画的数值显示进度,百分制的小数表示。
startValue和endValue分别对应ofInt(int start,int end)中的start和end的数值;
*/
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
//也就是 当前的值 = 100 + (400 - 100)* 显示进度
}
}
自定义Evaluator
public class MyEvaluator implements TypeEvaluator<Integer> {
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int) (200 + startInt + fraction * (endValue - startInt));
}
}
3.使用
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setEvaluator(new IntEvaluator());
...
4.1.8 ValueAnimator XML实现
标签<animator />对应ValueAnimator
4.1.8.1 animator所有的字段及取值范围
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]
android:interpolator=["@android:interpolator/XXX"]/>
android:valueType:表示参数值类型,取值为intType和floatType;
与android:valueFrom、android:valueTo相对应。
如果这里的取值为intType,那么android:valueFrom、android:valueTo的值也就要对应的是int类型的数值。
非常注意的是,如果android:valueFrom、android:valueTo的值设置为color类型的值,那么不需要设置这个参数;
4.1.8.2 代码实现
1.在res/animator目录下创建animator_value.xml
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0"
android:valueTo="300"
android:valueType="intType"
android:duration="1000"
android:interpolator="@android:anim/bounce_interpolator"
/>
2.加载到程序中
ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animtor_value);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int offset = (int) animation.getAnimatedValue();
tvAnimPropertyValue.layout(offset,offset,offset+tvAnimPropertyValue.getWidth(),offset+tvAnimPropertyValue.getHeight());
}
});
animator.start();