**
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