1 ValueAnimator和估值器简介
属性动画从API11 开始提供,动画实现主要依靠ValueAnimator和ObjectAnimator两个类,类,属性动画所在包为android.animation.Animator,和补间动画有明显区别,补间动画在android.view.animation包目录下,也说明了属性动画不单单作用于view。
ValueAnimator是属性动画中重要且最基本的类,ObjectAnimator内部也是借助ValueAnimator实现的。ValueAnimator直接子类有两个ObjectAnimator和TimeAnimator。
ValueAnimator是数值从初始值逐渐变化到结束值,无法直接作用于对象,只能通过设置动画监听,获取动画过程中的过渡值,然后设置对象的属性就可以实现动画。默认插值器为AccelerateDecelerateInterpolator,插值器只是动画执行的快慢的控制,控制具体动画过程中获取的值是通过估值器Evaluator来实现的。
ValueAnimator可以利用XML文件生成和java代码生成ValueAnimator类两种方式实现动画。
2 代码方式生成ValueAnimator
ValueAnimator初始化函数:
- ValueAnimator.ofInt(int ... values)//处理整形参数
- ValueAnimator.ofFloat(float ... values)//处理浮点型
- ValueAnimator. ofArgb(int... values) //处理颜色
- ValueAnimator.ofObject(TypeEvaluator evaluator, Object... values)//处理object对象,需要自定义估值器
- ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder... values) //处理PropertyValuesHolder
ValueAnimator使用过程:
- 第一步:利用上面的函数生成ValueAnimator对象,
- 第二步:设置动画的监听, addUpdateListener(ValueAnimator.AnimatorUpdateListener listener)
- 第三第:四步利用添加的监听函数获取当前动画的值,getAnimatedValue()
- 第四步:设置给View,实现动画
属性动画一般用代码生成(因为属性值无法写死在代码中,一般需要动态获取),所以本篇主要讲解代码生成方式,XML方式会提一下使用过程。
3 XML方式生成属性动画
XML生成属性动画三种标签:
: 对应ValueAnimator : 对应ObjectAnimator : 对应AnimatorSet
通用属性设置和补间动画类似,本篇主要讲解ValueAnimator,所以标签主要讲解。
举例:
定义XML文件
API23 之后还可以利用PropertyValuesHolder和keyframe实现
利用AnimatorInflater加载上面定义的xml文件,生成Animator实例
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.antorXML);
//如果是ObjectAnimator设置动画对象,如果是ValueAnimator则不需要设置target
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float name = (float) animation.getAnimatedValue();
}
});
animator.setTarget(view);
animator.start();
xml具体使用步骤总结:
- 第一步利用XML动画文件和AnimatorInflater生成ValueAnimator对象
- 第二步设置动画监听
- 第三步获取监听的动画值
- 第四步设置给view,执行动画
4 ValueAnimator代码方式详解
属性动画最好用代码实现,所以这篇文章也主要侧重代码实现。ValueAnimator无法像ObjectAnimator一样直接作用于对象,只能通过添加监听,获取动画过程之,然后手动设置给对象改变对象的属性。
4.1 ValueAnimator.ofInt(int ... values)
values可以有多个值,ofInt作用是从初始值(参数中的第一个)以整数形式过渡到结束值,如果参数有多个,那就是从初始值过渡到第二个参数,然后从第二个参数过渡到第三个参数,后面以此类推。
mBtn = findViewById(R.id.btn);
imageView = findViewById(R.id.imageview);
valueAnimator = ValueAnimator.ofInt(1, 10);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int data = (int) animation.getAnimatedValue();
System.out.println("========getAnimatedValue========="+data);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
@Override
public void onAnimationPause(Animator animation) {
super.onAnimationPause(animation);
}
@Override
public void onAnimationResume(Animator animation) {
super.onAnimationResume(animation);
}
});
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (valueAnimator.isRunning()){
valueAnimator.cancel();
}
valueAnimator.start();
}
});
输出结果:
ofInt函数,获取到的值都是整形。
========getAnimatedValue=========1
========getAnimatedValue=========1
========getAnimatedValue=========1
========getAnimatedValue=========2
========getAnimatedValue=========4
========getAnimatedValue=========6
========getAnimatedValue=========8
========getAnimatedValue=========9
========getAnimatedValue=========9
========getAnimatedValue=========10
前面我们说了除了插值器,属性动画还用到了估值器Evaluator,但是使用ofInt时我们却没有设置估值器,为什么呢?
通过setEvaluator函数上上面的注释,可以知道当使用ofInt,ofFLoat时系统会自动根据startValue和endValue给动画指定估值器。
使用ofInt是使用的估值器是IntEvaluator,使用ofFloat是使用的估值器是FloatEvaluator。
分析IntEvaluator
public class IntEvaluator implements TypeEvaluator {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
实现TypeEvaluator,实现了evaluate函数,evaluate三个参数的意义:
fraction:动画运行了多久,[0-1]的规范化数据,如果设置duration为1000ms,达到100ms时,fraction值为0.1,200ms为0.2。
startvalue:开始变化的值,
endValue:变化结束的值。
TypeEvaluator的evaluate函数返回值为(int)(startInt + fraction * (endValue - startInt)),
很简单就是开始值加上动画运行的时间乘以(结束值减去开始值)。
ofFloat代码举例:
ofFloat和onInt用法相同,只是数值精度不同,不再单独讲解,举个例子:
valueAnimator = ValueAnimator.ofFloat(1,0.5f);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float data = (float) animation.getAnimatedValue();
Matrix matrix = new Matrix();
matrix.setScale(data,data);
//ImageView要支持matrix,需要设置ImageView的ScaleType为matrix
imageView.setImageMatrix(matrix);
}
});
4.2 ofArgb 颜色渐变
ofArgb是api21提供的新方法,可以帮助我们实现颜色的渐变:
public static ValueAnimator ofArgb(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
anim.setEvaluator(ArgbEvaluator.getInstance());
return anim;
}
ofArgb内部利用ArgbEvaluator估值器计算动画运行期间的过渡颜色,所以颜色过渡的算法一定在ArgbEvaluator的evaluate方法中。
valueAnimator = ValueAnimator.ofArgb(Color.RED, Color.GREEN);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int data = (int) animation.getAnimatedValue();
imageView.setBackgroundColor(data);
textView.setBackgroundColor(data);
}
});
4.3 ofObject()
方法:
ofObject(TypeEvaluator evaluator, Object... values)
参数说明:
- evaluator:自定义估值器
- values:开始结束对象
** ofObject处理对象,需要传入自定义估值器,告诉系统如何计算动画运行过程中的值。**
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
ValueAnimator anim = new ValueAnimator();
anim.setObjectValues(values);
anim.setEvaluator(evaluator);
return anim;
}
需要自定义估值器,内部会设置自定义的估值器。
如何自定义估值器
** 上面已经分析了IntEvaluator的代码,下面直接举例定义一个既能改变颜色,又能改变view高度的估值器。**
首先定义用到的类,存储属性值:
public class HeightAndColor {
private int color;
private int height;
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
定义估值器Evaluator
其中颜色渐变利用的RgbaEvaluator的算法。
public class HeightAndColorEvaluator implements TypeEvaluator {
@Override
public HeightAndColor evaluate(float fraction, HeightAndColor startValue, HeightAndColor endValue) {
int startHeight = startValue.getHeight();
int currHeight = (int) (startHeight + fraction * (endValue.getHeight() - startHeight));
int currColor = getCurrRGBA(fraction, startValue.getColor(), endValue.getColor());
HeightAndColor heightAndColor = new HeightAndColor();
heightAndColor.setColor(currColor);
heightAndColor.setHeight(currHeight);
return heightAndColor;
}
public int getCurrRGBA(float fraction,int startValue,int endValue){
int startInt = startValue;
float startA = ((startInt >> 24) & 0xff) / 255.0f;
float startR = ((startInt >> 16) & 0xff) / 255.0f;
float startG = ((startInt >> 8) & 0xff) / 255.0f;
float startB = ( startInt & 0xff) / 255.0f;
int endInt = endValue;
float endA = ((endInt >> 24) & 0xff) / 255.0f;
float endR = ((endInt >> 16) & 0xff) / 255.0f;
float endG = ((endInt >> 8) & 0xff) / 255.0f;
float endB = ( endInt & 0xff) / 255.0f;
// convert from sRGB to linear
startR = (float) Math.pow(startR, 2.2);
startG = (float) Math.pow(startG, 2.2);
startB = (float) Math.pow(startB, 2.2);
endR = (float) Math.pow(endR, 2.2);
endG = (float) Math.pow(endG, 2.2);
endB = (float) Math.pow(endB, 2.2);
// compute the interpolated color in linear space
float a = startA + fraction * (endA - startA);
float r = startR + fraction * (endR - startR);
float g = startG + fraction * (endG - startG);
float b = startB + fraction * (endB - startB);
// convert back to sRGB in the [0..255] range
a = a * 255.0f;
r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;
g = (float) Math.pow(g, 1.0 / 2.2) * 255.0f;
b = (float) Math.pow(b, 1.0 / 2.2) * 255.0f;
return Math.round(a) << 24 | Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
}
}
使用定义的估值器:
HeightAndColor heightAndColor1 = new HeightAndColor();
heightAndColor1.setHeight(200);
heightAndColor1.setColor(Color.RED);
HeightAndColor heightAndColor2 = new HeightAndColor();
heightAndColor2.setHeight(400);
heightAndColor2.setColor(Color.GREEN);
valueAnimator = ValueAnimator.ofObject(new HeightAndColorEvaluator(), heightAndColor1, heightAndColor2);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
HeightAndColor data = (HeightAndColor) animation.getAnimatedValue();
textView.setBackgroundColor(data.getColor());
ViewGroup.LayoutParams lp = textView.getLayoutParams();
lp.height=data.getHeight();
textView.setLayoutParams(lp);
}
});
5 ofPropertyValuesHolder
PropertyValuesHolder类:
这个类持有一个属性名和对应的多个属性值,动画运行过程中会返回这种类型。ValueAnimator.ofInt(),ValueAnimator.ofFloat()等所有的函数内部都是把值存储到PropertyValuesHolder中。
ValueAnimator.ofInt函数
public static ValueAnimator ofInt(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
return anim;
}
//把值存入PropertyValuesHolder中
public void setIntValues(int... values) {
if (values == null || values.length == 0) {
return;
}
if (mValues == null || mValues.length == 0) {
setValues(PropertyValuesHolder.ofInt("", values));
} else {
PropertyValuesHolder valuesHolder = mValues[0];
valuesHolder.setIntValues(values);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
所以PropertyValuesHolder是Animator内部存储数据用的。
用法实例:
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("str1", 1,2,3);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("str2", 4,5,6);
valueAnimator = ValueAnimator.ofPropertyValuesHolder(propertyValuesHolder1,propertyValuesHolder2);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float name = (float) animation.getAnimatedValue("str1");
float age = (float) animation.getAnimatedValue("str2");
System.out.println("======1111========"+name+" "+age);
}
});
输出结果:
======1111========1.0 4.0
======1111========1.0 4.0
======1111========1.034 4.034
======1111========1.266 4.266
======1111========1.5339999 4.534
======1111========1.766 4.766
======1111========2.0 5.0
======1111========2.266 5.266
======1111========2.534 5.534
======1111========2.8 5.8
======1111========3.0 6.0
Animation.getAnimatedValue(“propertyName”)就可以获取到对应的值。
PropertyValuesHolder的ofXX函数比较多:
ofFloat(Property, Float> property, float... values)
ofFloat(String propertyName, float... values)
ofInt(String propertyName, int... values)
ofInt(Property, Integer> property, int... values)
ofKeyframe(String propertyName, Keyframe... values)
ofKeyframe(Property property, Keyframe... values)
ofMultiFloat(String propertyName, float[][] values)
ofMultiFloat(String propertyName, TypeConverter converter, TypeEvaluator evaluator, V... values)
ofMultiFloat(String propertyName, Path path)
ofMultiFloat(String propertyName, TypeConverter converter, TypeEvaluator evaluator, Keyframe... values)
ofMultiInt(String propertyName, TypeConverter converter, TypeEvaluator evaluator, V... values)
ofObject(String propertyName, TypeConverter converter, Path path)
ofObject(String propertyName, TypeEvaluator evaluator, Object... values)
ofObject(Property, V> property, TypeConverter converter, TypeEvaluator evaluator, T... values)
。。。。。。
要讲解完所有的PropertyValuesHolder函数篇幅太大,后面会另开文章讲解。
Animation动画概述和执行原理
Android动画之补间动画TweenAnimation
Android动画之逐帧动画FrameAnimation
Android动画之插值器简介和系统默认插值器
Android动画之插值器Interpolator自定义
Android动画之视图动画的缺点和属性动画的引入
Android动画之ValueAnimator用法和自定义估值器
Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性
Android动画之ObjectAnimator中ofXX函数全解析-自定义Property,TypeConverter,TypeEvaluator
Android动画之AnimatorSet联合动画用法
Android动画之LayoutTransition布局动画
Android动画之共享元素动画
Android动画之ViewPropertyAnimator(专用于view的属性动画)
Android动画之Activity切换动画overridePendingTransition实现和Theme Xml方式实现
Android动画之ActivityOptionsCompat概述
Android动画之场景变换Transition动画的使用
Android动画之Transition和TransitionManager使用
Android动画之圆形揭露动画Circular Reveal
Android 动画之 LayoutAnimation 动画
Android动画之视图动画的缺点和属性动画的引入