ValueAnimator
ValueAnimator在属性动画中占有非常重要的地位,它是属性动画的核心所在,ValueAnimator本身不提供任何动画效果,它像一个数值发生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程,通常情况下没在ValueAnimator的AnimatorUpdateListener中监听数值的变换,从而完成动画的变换。
private void setValueAnim(){
ValueAnimator animator=ValueAnimator.ofFloat(0,100);
animator.setDuration(1000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value=(Float)animation.getAnimatedValue();
//TODO use the value
}
});
}
ObjectAnimator
ObjectAnimator是属性动画框架中最重要的实行类,它其实是继承自ValueAnimator的,在使用ObjectAnimator的时候,有一点非常重要,那就是要操纵的属性必须具有get,set方法,不然ObjectAnimator就无法起效。
private void setObjectAnim(){
ObjectAnimator animator=ObjectAnimator.ofFloat(iv,"rotation",0,360);
animator.setDuration(1000);
animator.start();
}
1.translationX和translationY:这两个属性控制view对象从它布局容器的左上角坐标偏移的位置。
2.rotation、rotationX和rotationY:这三个属性控制view对象围绕支点进行2D和3D旋转。
3.scaleX和scaleY:这两个属性控制着view围绕它的支点进行2D缩放。
4.pivotX和pivotY:这两个属性控制着view对象的支点位置,围绕这个支点进行旋转和缩放变换处理。
5.alpha:控制对象的透明度。
PropertyValuesHolder
在属性动画中,如果针对同一个对象的多个属性,要同时作用多种动画,可以使用PropertyValuesHolder来实现。
private void setPropertyAnim(){
PropertyValuesHolder pvh1=PropertyValuesHolder.ofFloat("translationX",300f);
PropertyValuesHolder pvh2=PropertyValuesHolder.ofFloat("scaleX",1f,0.1f);
PropertyValuesHolder pvh3=PropertyValuesHolder.ofFloat("scaleY",1f,0.1f);
ObjectAnimator.ofPropertyValuesHolder(iv,pvh1,pvh2,pvh3)
.setDuration(1000).start();
}
AnimatorSet
对于一个对象同时作用多个属性动画效果,AnimatorSet不仅能实现这样的效果,同时也能实现更为精确的顺序控制。
private void setObjectAnim(){
ObjectAnimator animator1=ObjectAnimator.ofFloat(iv,"translationX",300f);
ObjectAnimator animator2=ObjectAnimator.ofFloat(iv,"scaleX",1f,0f,1f);
ObjectAnimator animator3=ObjectAnimator.ofFloat(iv,"scaleY",1f,0f,1f);
AnimatorSet set=new AnimatorSet();
set.setDuration(1000);
set.playTogether(animator1,animator2,animator3);
set.start();
}
Animator监听器
在很多时候,我们希望可以监听到动画的各种事件,比如动画何时开始,何时结束,然后在开始或者结束的时候去执行一些逻辑处理.
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
}
});
XML编写动画
三种标签:
透明度变化xml
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" android:propertyName="alpha"/>
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
ValueAnimator的高级用法
在开始动手之前,我们还需要掌握另外一个知识点,就是TypeEvaluator的用法,那么TypeEvaluator的作用到底是什么呢?简单来说,就是告诉动画系统如何从初始值过度到结束值。
ValueAnimator.ofFloat()方法就是实现了初始值与结束值之间的平滑过度,那么这个平滑过度是怎么做到的呢?其实就是系统内置了一个FloatEvaluator,它通过计算告知动画系统如何从初始值过度到结束值,我们来看一下FloatEvaluator的代码实现:
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
evaluate()方法当中传入了三个参数,第一个参数fraction非常重要,这个参数用于表示动画的完成度的,第二第三个参数分别表示动画的初始值和结束值。那么上述代码的逻辑就比较清晰了,用结束值减去初始值,算出它们之间的差值,然后乘以fraction这个系数,再加上初始值,那么就得到当前动画的值了。
我们使用过了ValueAnimator的ofFloat()和ofInt()方法,分别用于对浮点型和整型的数据进行动画操作的,但实际上ValueAnimator中还有一个ofObject()方法,是用于对任意对象进行动画操作的。
先定义一个Point类,如下所示:
public class Point {
private float x;
private float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
接下来定义PointEvaluator,如下所示:
public class PointEvaluator implements TypeEvaluator{
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint=(Point)startValue;
Point endPoint=(Point)endValue;
float x=startPoint.getX()+fraction*(endPoint.getX()-startPoint.getX());
float y=startPoint.getY()+fraction*(endPoint.getY()-startPoint.getY());
Point point=new Point(x,y);
return point;
}
}
PointEvaluator同样实现了TypeEvaluator接口并重写了evaluate()方法。比如说我们有两个Point对象,现在需要将Point1通过动画平滑过度到Point2,就可以这样写:
Point point1=new Point(0,0);
Point point2=new Point(500,500);
ValueAnimator animator=ValueAnimator.ofObject(new PointEvaluator(),point1,point2);
animator.setDuration(2000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Point value=(Point)animation.getAnimatedValue();
Log.i("=======",value.getX()+"======"+value.getY());
}
});
尝试一下如何通过对Point对象进行动画操作,从而实现整个自定义View的动画效果。
新建一个MyAnimView继承自View,代码如下所示:
public class MyAnimView extends View{
public static final float RADIUS=50f;
private Paint mPaint;
private Point currentPoint;
public MyAnimView(Context context) {
super(context);
}
public MyAnimView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(currentPoint==null){
currentPoint=new Point(RADIUS,RADIUS);
drawCircle(canvas);
startAnimation();
}else{
drawCircle(canvas);
}
}
private void drawCircle(Canvas canvas){
float x=currentPoint.getX();
float y=currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
private void startAnimation(){
Point startPoint=new Point(RADIUS,RADIUS);
Point endPoint=new Point(getWidth()-RADIUS,getHeight()-RADIUS);
ValueAnimator animator=ValueAnimator.ofObject(new PointEvaluator(),startPoint,endPoint);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint=(Point)animation.getAnimatedValue();
invalidate();
}
});
animator.setDuration(5000);
animator.setRepeatCount(-1);
animator.setRepeatMode(Animation.REVERSE);
animator.start();
}
}
ObjectAnimator的高级用法
想要实现对View的颜色进行动态改变。
要在MyAnimView中定义一个color属性,并提供它的get和set方法。
public class MyAnimView extends View {
...
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
mPaint.setColor(Color.parseColor(color));
invalidate();
}
...
}
编写一个用于告知系统如何进行颜色过度的TypeEvaluator,代码如下所示:
import android.animation.TypeEvaluator;
public class ColorEvaluator implements TypeEvaluator{
private int mCurrentRed = -1;
private int mCurrentGreen = -1;
private int mCurrentBlue = -1;
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
String startColor = (String) startValue;
String endColor = (String) endValue;
int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);
int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);
// 初始化颜色的值
if (mCurrentRed == -1) {
mCurrentRed = startRed;
}
if (mCurrentGreen == -1) {
mCurrentGreen = startGreen;
}
if (mCurrentBlue == -1) {
mCurrentBlue = startBlue;
}
// 计算初始颜色和结束颜色之间的差值
int redDiff = Math.abs(startRed - endRed);
int greenDiff = Math.abs(startGreen - endGreen);
int blueDiff = Math.abs(startBlue - endBlue);
int colorDiff = redDiff + greenDiff + blueDiff;
if (mCurrentRed != endRed) {
mCurrentRed = getCurrentColor(startRed, endRed, colorDiff, 0,
fraction);
} else if (mCurrentGreen != endGreen) {
mCurrentGreen = getCurrentColor(startGreen, endGreen, colorDiff,
redDiff, fraction);
} else if (mCurrentBlue != endBlue) {
mCurrentBlue = getCurrentColor(startBlue, endBlue, colorDiff,
redDiff + greenDiff, fraction);
}
// 将计算出的当前颜色的值组装返回
String currentColor = "#" + getHexString(mCurrentRed)
+ getHexString(mCurrentGreen) + getHexString(mCurrentBlue);
return currentColor;
}
/** * 根据fraction值来计算当前的颜色。 */
private int getCurrentColor(int startColor, int endColor, int colorDiff,
int offset, float fraction) {
int currentColor;
if (startColor > endColor) {
currentColor = (int) (startColor - (fraction * colorDiff - offset));
if (currentColor < endColor) {
currentColor = endColor;
}
} else {
currentColor = (int) (startColor + (fraction * colorDiff - offset));
if (currentColor > endColor) {
currentColor = endColor;
}
}
return currentColor;
}
/** * 将10进制颜色值转换成16进制。 */
private String getHexString(int value) {
String hexString = Integer.toHexString(value);
if (hexString.length() == 1) {
hexString = "0" + hexString;
}
return hexString;
}
}
修改MyAnimView中的代码,如下所示:
private void startAnimation(){
Point startPoint=new Point(RADIUS,RADIUS);
Point endPoint=new Point(getWidth()-RADIUS,getHeight()-RADIUS);
ValueAnimator animator=ValueAnimator.ofObject(new PointEvaluator(),startPoint,endPoint);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint=(Point)animation.getAnimatedValue();
invalidate();
}
});
ObjectAnimator anim = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
"#0000FF", "#FF0000");
AnimatorSet animSet = new AnimatorSet();
animSet.play(animator).with(anim);
animSet.setDuration(5000);
animSet.start();
}
Interpolator和ViewPropertyAnimator的用法
参见这里写链接内容