实现这样的效果,你要知道贝塞尔曲线,何谓贝塞尔曲线?其实就是曲线,嘿嘿,关于曲线的概念大家可以去
Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解
中看下,我们这里就直接写了
1.activity_main.xml
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent">//撒花的区域<relativelayoutandroid:id="@+id/rlt_animation_layout"android:layout_width="match_parent"android:layout_height="match_parent"></relativelayout><buttonandroid:id="@+id/btn_start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignparentbottom="true"android:layout_centerhorizontal="true"android:layout_marginbottom="23dp"android:text="开始撒花"></button> </relativelayout>
2.Fllower
package com.lgl.test;import android.graphics.Bitmap; import android.graphics.Path;import java.io.Serializable;public class Fllower implements Serializable {private static final long serialVersionUID = 1L;private Bitmap image;private float x;private float y;private Path path;private float value;public Bitmap getResId() {return image;}public void setResId(Bitmap img) {this.image = img;}public float getX() {return x;}public void setX(float x) {this.x = x;}public float getY() {return y;}public void setY(float y) {this.y = y;}public Path getPath() {return path;}public void setPath(Path path) {this.path = path;}public float getValue() {return value;}public void setValue(float value) {this.value = value;}@Overridepublic String toString() {return "Fllower [ x=" + x + ", y=" + y + ", path=" + path + ", value="+ value + "]";}}
3.FllowerAnimation 动画类
package com.lgl.test;import java.util.ArrayList; import java.util.List; import java.util.Random;import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator;/*** 撒花 用到的知识点: 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 = 400;int[] ylocations = { -100, -50, -25, 0 };/*** 资源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, ylocations[random.nextInt(3)]);List<cpoint> points = builderPath(CPoint);drawFllowerPath(path, points);Fllower fllower = new Fllower();fllower.setPath(path);Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.lift_flower);fllower.setResId(bitmap);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 pathif (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;@Overrideprotected 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);canvas.drawBitmap(fllower.getResId(), pos[0], pos[1] - dy, null);}}ObjectAnimator mAnimator1;ObjectAnimator mAnimator2;ObjectAnimator mAnimator3;public void startAnimation() {if (mAnimator1 != null && mAnimator1.isRunning()) {mAnimator1.cancel();}mAnimator1 = ObjectAnimator.ofFloat(this, "phase1", 0f, 1f);mAnimator1.setDuration(time);mAnimator1.addUpdateListener(this);mAnimator1.start();mAnimator1.setInterpolator(new AccelerateInterpolator(1f));if (mAnimator2 != null && mAnimator2.isRunning()) {mAnimator2.cancel();}mAnimator2 = ObjectAnimator.ofFloat(this, "phase2", 0f, 1f);mAnimator2.setDuration(time);mAnimator2.addUpdateListener(this);mAnimator2.start();mAnimator2.setInterpolator(new AccelerateInterpolator(1f));mAnimator2.setStartDelay(delay);if (mAnimator3 != null && mAnimator3.isRunning()) {mAnimator3.cancel();}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);}}/*** 动画改变回调*/@Overridepublic 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.MainActivity
package com.lgl.test;import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.RelativeLayout;public class MainActivity extends Activity {private Button btn_start;// 撒花特效private RelativeLayout rlt_animation_layout;private FllowerAnimation fllowerAnimation;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 撒花初始化rlt_animation_layout = (RelativeLayout) findViewById(R.id.rlt_animation_layout);rlt_animation_layout.setVisibility(View.VISIBLE);fllowerAnimation = new FllowerAnimation(this);RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT);fllowerAnimation.setLayoutParams(params);rlt_animation_layout.addView(fllowerAnimation);btn_start = (Button) findViewById(R.id.btn_start);btn_start.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 开始撒花 fllowerAnimation.startAnimation();}});} }