1、前言
今天項目要用到一個類似微信發送麼麼噠,那種屏幕飄表情的功能,所以分析研究了一下,用到的技術應該是路徑動畫,不知道這樣就正不正確,反正就是畫一個路徑線,然後對象根據這個路徑去運動。所以就叫他路徑動畫了。
路徑動畫要首先要解決的問題就是怎麼畫這個路徑?然後路徑畫出來後怎麼取路徑上的所有點的座標值?
這裏解決這兩個問題就看一個類PathMeasure 這個類接收一個path對象,然後可以根據pathMeasure.getPosTan()可以得到長度比例的座標值。這兩個問題就直接搞定了。用path畫一個路徑然後取點,動態移動對象,就變成了路徑動畫了。是不是很簡單。
2、看效果
3、核心代碼
/**
* 撒花
*
* @author yd
*
用到的知識點:
1、android屬性動畫
2、Path路徑繪製
3、貝塞爾曲線
*
*
*
*
*
*
*
*
*/
public class FllowerAnimation extends View implements AnimatorUpdateListener {
/**
* 動畫改變的屬性值
*/
private float phase1 = 0f;
private float phase2 = 0f;
private float phase3 = 0f;
/**
* 小球集合
*/
private List<Fllower> fllowers1 = new ArrayList<Fllower>();
private List<Fllower> fllowers2 = new ArrayList<Fllower>();
private List<Fllower> fllowers3 = new ArrayList<Fllower>();
/**
* 動畫播放的時間
*/
private int time = 4000;
/**
* 動畫間隔
*/
private int delay = 500;
/**
* 資源ID
*/
// private int resId = R.drawable.fllower_love;
public FllowerAnimation(Context context) {
super(context);
init(context);
// this.resId = resId;
}
@SuppressWarnings("deprecation")
private void init(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
width = wm.getDefaultDisplay().getWidth();
height = (int) (wm.getDefaultDisplay().getHeight() * 3 / 2f);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(2);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Style.STROKE);
pathMeasure = new PathMeasure();
builderFollower(fllowerCount, fllowers1);
builderFollower(fllowerCount , fllowers2);
builderFollower(fllowerCount , fllowers3);
}
/**
* 寬度
*/
private int width = 0;
/**
* 高度
*/
private int height = 0;
/**
* 曲線高度個數分割
*/
private int quadCount = 10;
/**
* 曲度
*/
private float intensity = 0.2f;
/**
* 第一批個數
*/
private int fllowerCount = 4;
/**
* 創建花
*/
private void builderFollower(int count, List<Fllower> fllowers) {
int max = (int) (width * 3 / 4f);
int min = (int) (width / 4f);
Random random = new Random();
for (int i = 0; i < count; i++) {
int s = random.nextInt(max) % (max - min + 1) + min;
Path path = new Path();
CPoint CPoint = new CPoint(s, 0);
List<CPoint> points = builderPath(CPoint);
drawFllowerPath(path, points);
Fllower fllower = new Fllower();
fllower.setPath(path);
fllowers.add(fllower);
}
}
/**
* 畫曲線
* @param path
* @param points
*/
private void drawFllowerPath(Path path, List<CPoint> points) {
if (points.size() > 1) {
for (int j = 0; j < points.size(); j++) {
CPoint point = points.get(j);
if (j == 0) {
CPoint next = points.get(j + 1);
point.dx = ((next.x - point.x) * intensity);
point.dy = ((next.y - point.y) * intensity);
} else if (j == points.size() - 1) {
CPoint prev = points.get(j - 1);
point.dx = ((point.x - prev.x) * intensity);
point.dy = ((point.y - prev.y) * intensity);
} else {
CPoint next = points.get(j + 1);
CPoint prev = points.get(j - 1);
point.dx = ((next.x - prev.x) * intensity);
point.dy = ((next.y - prev.y) * intensity);
}
// create the cubic-spline path
if (j == 0) {
path.moveTo(point.x, point.y);
} else {
CPoint prev = points.get(j - 1);
path.cubicTo(prev.x + prev.dx, (prev.y + prev.dy),
point.x - point.dx, (point.y - point.dy),
point.x, point.y);
}
}
}
}
/**
* 曲線搖擺的幅度
*/
private int range = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 70, getResources().getDisplayMetrics());
/**
* 畫路徑
*
* @param point
* @return
*/
private List<CPoint> builderPath(CPoint point) {
List<CPoint> points = new ArrayList<CPoint>();
Random random = new Random();
for (int i = 0; i < quadCount; i++) {
if (i == 0) {
points.add(point);
} else {
CPoint tmp = new CPoint(0, 0);
if (random.nextInt(100) % 2 == 0) {
tmp.x = point.x + random.nextInt(range);
} else {
tmp.x = point.x - random.nextInt(range);
}
tmp.y = (int) (height / (float) quadCount * i);
points.add(tmp);
}
}
return points;
}
/**
* 畫筆
*/
private Paint mPaint;
/**
* 測量路徑的座標位置
*/
private PathMeasure pathMeasure = null;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawFllower(canvas, fllowers1);
drawFllower(canvas, fllowers2);
drawFllower(canvas, fllowers3);
}
/**
* 高度往上偏移量,把開始點移出屏幕頂部
*/
private float dy = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,40, getResources().getDisplayMetrics());
/**
*
* @param canvas
* @param fllowers
*/
private void drawFllower(Canvas canvas, List<Fllower> fllowers) {
for (Fllower fllower : fllowers) {
float[] pos = new float[2];
canvas.drawPath(fllower.getPath(),mPaint);
pathMeasure.setPath(fllower.getPath(), false);
pathMeasure.getPosTan(height * fllower.getValue(), pos, null);
canvas.drawCircle(pos[0], pos[1], 10, mPaint);
// Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);
// canvas.drawBitmap(bitmap, pos[0], pos[1] - dy, null);
// bitmap.recycle();
}
}
public void startAnimation() {
ObjectAnimator mAnimator1 = ObjectAnimator.ofFloat(this, "phase1", 0f,
1f);
mAnimator1.setDuration(time);
mAnimator1.addUpdateListener(this);
mAnimator1.start();
mAnimator1.setInterpolator(new AccelerateInterpolator(1f));
ObjectAnimator mAnimator2 = ObjectAnimator.ofFloat(this, "phase2", 0f,
1f);
mAnimator2.setDuration(time);
mAnimator2.addUpdateListener(this);
mAnimator2.start();
mAnimator2.setInterpolator(new AccelerateInterpolator(1f));
mAnimator2.setStartDelay(delay);
ObjectAnimator mAnimator3 = ObjectAnimator.ofFloat(this, "phase3", 0f,
1f);
mAnimator3.setDuration(time);
mAnimator3.addUpdateListener(this);
mAnimator3.start();
mAnimator3.setInterpolator(new AccelerateInterpolator(1f));
mAnimator3.setStartDelay(delay * 2);
}
/**
* 跟新小球的位置
*
* @param value
* @param fllowers
*/
private void updateValue(float value, List<Fllower> fllowers) {
for (Fllower fllower : fllowers) {
fllower.setValue(value);
}
}
/**
* 動畫改變回調
*/
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
updateValue(getPhase1(), fllowers1);
updateValue(getPhase2(), fllowers2);
updateValue(getPhase3(), fllowers3);
Log.i(tag, getPhase1() + "");
invalidate();
}
public float getPhase1() {
return phase1;
}
public void setPhase1(float phase1) {
this.phase1 = phase1;
}
public float getPhase2() {
return phase2;
}
public void setPhase2(float phase2) {
this.phase2 = phase2;
}
public float getPhase3() {
return phase3;
}
public void setPhase3(float phase3) {
this.phase3 = phase3;
}
private String tag = this.getClass().getSimpleName();
private class CPoint {
public float x = 0f;
public float y = 0f;
/** x-axis distance */
public float dx = 0f;
/** y-axis distance */
public float dy = 0f;
public CPoint(float x, float y) {
this.x = x;
this.y = y;
}
}
}
4、項目地址
http://download.csdn.net/detail/hxc2008q/8473053