zoukankan      html  css  js  c++  java
  • 仿QQ撒花特效--第三方开源--FllowerAnimation

    点此下载资源

    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" >
    
        //撒花的区域
        <RelativeLayout
            android:id="@+id/rlt_animation_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
        </RelativeLayout>
    
        <Button
            android: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="开始撒花" />
    
    </RelativeLayout>

    Fllower.java

    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;
        }
    
        @Override
        public String toString() {
            return "Fllower [ x=" + x + ", y=" + y + ", path=" + path + ", value="
                    + value + "]";
        }
    
    }

    FllowerAnimation.java:

    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 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);
                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);
            }
        }
    
        /**
         * 动画改变回调
         */
        @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;
            }
        }
    
    }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 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);
                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);
            }
        }
    
        /**
         * 动画改变回调
         */
        @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;
            }
        }
    
    }

    MainActivity.java:

    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;
    
        @Override
        protected 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() {
    
                @Override
                public void onClick(View v) {
                    // 开始撒花
                    fllowerAnimation.startAnimation();
                }
            });
        }
    }
  • 相关阅读:
    hdu 刷题记录
    HDU step by step
    Codeforces Round #260 (Div. 2) B. Fedya and Maths
    Codeforces Round #260 (Div. 2) A. Laptops
    UVALive 6662 TheLastAnt
    UVALive 6661 Equal Sum Sets
    Codeforces Round #253 (Div. 2) A. Anton and Letters
    wikioi 3130 CYD刷题(背包)
    wikioi 1014 装箱问题(背包)
    [转]很特别的一个动态规划入门教程
  • 原文地址:https://www.cnblogs.com/zzw1994/p/5200032.html
Copyright © 2011-2022 走看看