首先扯点别的:晚上稍微跑了一会步,然后逛了超市,晚饭喝的南瓜粥,吃了一碗面条,今天不是太饿,现在正一边吃着葡萄一边学习,也是没谁了。
比如说,我们想要实现从0过渡到100,使用ValueAnimator 就可以这样写:
ValueAnimator va = ValueAnimator.ofInt(1, 00);
va.setDuration(3000);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.e("tag", "value : " + animation.getAnimatedValue());
}
});
va.start();
打印出来的结果就是从1到100;但是这是怎么实现的呢,这是因为系统内置了一个IntEvaluator(相当于一个计算器)来实现计算如何从动画的初始值过渡到结束值。
//IntEvaluator 的evaluate方法
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
//就返回初始值加上fraction乘上结束值减去初始值fraction变化范围0到1
return (int)(startInt + fraction * (endValue - startInt));
}
ValueAnimator有一个ofObject方法,用来操作对象的动画。但是和ofInt或者ofFloat方法相比,ofObject没法内置一个Evaluator,因为对象不同,计算的方式也不一样,所以要自己实现一个继承自TypeEvaluator的Evaluator。
使用场景:自定义一个View,View中有一个Point()对象用来管理坐标,View在onDraw方法中根据Point()对象的坐标进行绘制,然后使用ValueAnimator来改变Poin对象的坐标值,那么自定义View就会实现动画效果。
//具有x,y两个属性和相应的get,set函数
public class MyPoint {
private float x;
private float y;
public MyPoint(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<MyPoint> {
@Override
public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) {
//改变x值
float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
//改变y值
float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
MyPoint point = new MyPoint(x, y);
//返回一个新的Point对象,坐标已经改变了
return point;
}
}
新建一个PointAnimView 继承自View
public class PointAnimView extends View {
public static final float RADIUS = 50f; //point点的半径
private MyPoint currentPoint;
private Paint mPaint;
public PointAnimView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
@Override
protected void onDraw(Canvas canvas) {
//第一次绘制初始的点之后就启动动画
if (currentPoint == null) {
currentPoint = new MyPoint(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() {
MyPoint startPoint = new MyPoint(RADIUS, RADIUS);
MyPoint endPoint = new MyPoint(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (MyPoint) animation.getAnimatedValue();
invalidate();
}
});
anim.setDuration(5000);
anim.start();
}
}
将PointAnimView 引入布局文件使用。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hm.animationdemo.widget.PointAnimView
android:id="@+id/point_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
效果图
ObjectAnimator的高级用法
实现动态改变PointAnimView的颜色,那就得给PointAnimView添加color属性并提供相应的getColor方法和setColor方法,在setColor方法中改变View里面画笔的颜色,然后调用invalidate方法刷新视图,在绘制的时候,View的颜色就会发生变化
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
mPaint.setColor(Color.parseColor(color));
invalidate();
}
ObjectAnimator的ofObject方法
//可以看到第三个参数是一个TypeEvaluator ,用来计算Object的属性,在这里就是我们的color如何变化,
//所以要重写一个TypeEvaluator来计算颜色的变化
public static ObjectAnimator ofObject(Object target, String propertyName,
TypeEvaluator evaluator, Object... values)
//这个实现细节,就愉快的略过吧。
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;
}
}
定义好了ColorEvaluator ,就可以改变颜色了,改变MyAinmView中的startAnimation方法,就可以实现在改变view的位置的同时改变view的颜色了。
private void startAnimation() {
MyPoint startPoint = new MyPoint(RADIUS, RADIUS);
MyPoint endPoint = new MyPoint(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (MyPoint) animation.getAnimatedValue();
invalidate();
}
});
ObjectAnimator anim2 = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
"#0000FF", "#FF0000");
AnimatorSet animSet = new AnimatorSet();
animSet.play(anim).with(anim2);
animSet.setDuration(5000);
animSet.start();
}
效果如下
结尾:文章中的代码来自部分摘自郭霖老师的博客。是时候睡觉了。