**
Android动画集锦(属性动画)
**
先看效果图:
1、第一个图片的闪动光晕效果;
2、双重绘制圆形,利用线程定期画弧度;
3、利用线性函数绘制同心圆从0°到360°完整的路径;
4、将指定的view在指定的抛物线路径上做循环动画;
5、周期函数动画,x方向线性变化,y方向为周期函数:
y = 120 * sin(0.01 * π * x) + 200,从起始点(0,200)到结束点(600,200)之间的动画,并在动画过程中绘制路径和圆形。
周期函数动画代码如下:
/**
* TypeEvaluatorView 2019-11-19
*/
public class TypeEvaluatorView extends View {
private Paint circlePaint = new Paint();
private P currentP;
private float mRadius = 15f;
private int width;
private int height;
private Path path = new Path();
private Paint pathPaint = new Paint();
private static boolean isFirst = true;
private static int repeatCount = 0;
private int color[] = { 0xffffffff, 0xFFFF00FF, 0xffffff00, 0xff33ffff };
public TypeEvaluatorView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TypeEvaluatorView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public TypeEvaluatorView(Context context) {
super(context);
}
public void startAnimation() {
P startP = new P(0, getHeight() / 2);
P endP = new P(getWidth(), getHeight() / 2);
// 第一次画路径时,将path的起始位置设置为开始位置
if (isFirst) {
path.moveTo(0, getHeight() / 2);
}
ValueAnimator animator = ValueAnimator.ofObject(new OscillationEvaluator(), startP, endP);
animator.setDuration(5000).setRepeatCount(Integer.MAX_VALUE);
animator.setRepeatMode(Animation.REVERSE);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 拿到当前运动到的点位置
currentP = (P) animation.getAnimatedValue();
// 在起点和终点之间收集绘制路径
path.lineTo(currentP.getX(), currentP.getY());
// 重绘view
invalidate();
}
});
animator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@SuppressLint("NewApi")
@Override
public void onAnimationRepeat(Animator animation) {
isFirst = false;
repeatCount++;
// 重新设置path路径
path.reset();
// 根据动画的重复,设置路径的起点和终点
if (repeatCount % 2 == 0) {
// 偶数次起点在开始位置
path.moveTo(0, height / 2);
} else {
// 奇数次,起点在结束位置
path.moveTo(getWidth(), height / 2);
}
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
});
animator.setInterpolator(new LinearInterpolator());// 设置插值器
animator.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
width = getWidth();
height = getHeight();
// path.moveTo(0, height / 2);//炫酷的扇子形状
Paint linePaint = new Paint();
linePaint.setStyle(Style.STROKE);
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(3f);
linePaint.setColor(color[0]);
// 中间白线
canvas.drawLine(0, height / 2, width, height / 2, linePaint);
pathPaint.setStyle(Style.STROKE);
pathPaint.setAntiAlias(true);
pathPaint.setStrokeWidth(5f);
pathPaint.setColor(color[0]);
circlePaint.setStyle(Style.FILL);
circlePaint.setAntiAlias(true);
if (currentP == null) {
startAnimation();
}
// 设置不同的四种颜色
if (repeatCount % 4 == 0) {
circlePaint.setColor(color[0]);
pathPaint.setColor(color[0]);
} else if (repeatCount % 4 == 1) {
pathPaint.setColor(color[1]);
circlePaint.setColor(color[1]);
} else if (repeatCount % 4 == 2) {
pathPaint.setColor(color[2]);
circlePaint.setColor(color[2]);
} else {
pathPaint.setColor(color[3]);
circlePaint.setColor(color[3]);
}
// 画路径
canvas.drawPath(path, pathPaint);
// 第一次不画圆
if (repeatCount >= 1) {
canvas.drawCircle(currentP.getX(), currentP.getY(), mRadius, circlePaint);
}
}
class P {
private float x;
private float y;
/**
* @param x
* @param y
*/
public P(float x, float y) {
super();
this.x = x;
this.y = y;
}
/**
* @return the x
*/
public float getX() {
return x;
}
/**
* @param x
* the x to set
*/
public void setX(float x) {
this.x = x;
}
/**
* @return the y
*/
public float getY() {
return y;
}
/**
* @param y
* the y to set
*/
public void setY(float y) {
this.y = y;
}
}
class OscillationEvaluator implements TypeEvaluator<P> {
@Override
public P evaluate(float fraction, P startValue, P endValue) {
P startP = (P) startValue;
P endP = (P) endValue;
float x = startP.getX() + fraction * (endP.getX() - startP.getX());// x坐标线性变化
float y = 120 * (float) (Math.sin(0.01 * Math.PI * x)) + getHeight() / 2;// y坐标取相对应函数值
return new P(x, y);
}
}
}
将此自定义的view放在xml布局中即可,view的宽为600dp,高为400dp。
抛物线动画代码:
从(0,0)到(200,200)之间的动画轨迹
public void beginTranslateAnimation(final View view) {
ArrayList<Float> xvalues = new ArrayList<Float>();
xvalues.add(0f);
xvalues.add(200f);
ArrayList<Float> yvalues = new ArrayList<Float>();
yvalues.add(0f);
yvalues.add(200f);
final ObjectAnimator translateX = ObjectAnimator.ofObject(view, "translationX",
new CustomXTypeEvaluator(), xvalues.toArray());
final ObjectAnimator translateY = ObjectAnimator.ofObject(view, "translationY",
new CustomYTypeEvaluator(), yvalues.toArray());
translateX.setRepeatCount(Integer.MAX_VALUE);
translateX.setRepeatMode(ObjectAnimator.REVERSE);
translateX.setInterpolator(new LinearInterpolator());
translateY.setInterpolator(new AccelerateInterpolator());
translateY.setRepeatCount(Integer.MAX_VALUE);
translateY.setRepeatMode(ObjectAnimator.REVERSE);
// translateX.setInterpolator(new BounceInterpolator());
// translateX.setInterpolator(new CycleInterpolator(0.6f));
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(translateX, translateY);
animatorSet.setDuration(1000);
animatorSet.start();
view.invalidate();
}
x方向线性运动,CustomXTypeEvaluator.java:
/**
* TypeEvaluator 2019-11-26
*/
public class CustomXTypeEvaluator implements TypeEvaluator<Float> {
@Override
public Float evaluate(float f, Float startValue, Float endValue) {
float x = startValue + f * (endValue - startValue);
// float x = startValue * 1.2f;
return x;
}
}
y方向抛物线运动,CustomYTypeEvaluator.java:
/**
* TypeEvaluator 2019-11-26
*/
public class CustomYTypeEvaluator implements TypeEvaluator<Float> {
@Override
public Float evaluate(float f, Float startValue, Float endValue) {
float y = startValue + f * f * (endValue - startValue);
return y;
}
}
获取源代码加VX:13361000135