MUI卸载动画——粒子爆炸

二.MUI卸载动画——粒子爆炸关于这个粒子特效,在开篇的时候已经展示了效果,那么我们接下来,要怎么做尼?1.ParticleUtils
用于粒子动画的单位转换


package com.lgl.animview;

import android.content.res.Resources;

/** * 粒子动画 */
public class ParticleUtils {
    /** * 密度 */
    public static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;

    public static int dp2px(int dp) {
        return Math.round(dp * DENSITY);
    }
}

2.Particle
用于爆破效果的分子计算


package com.lgl.animview;

import java.util.Random;

import android.graphics.Point;
import android.graphics.Rect;

/** * Created by lgl on 16/01/14. 爆破粒子 */
public class Particle {

    public static final int PART_WH = 8; // 默认小球宽高

    // 原本的值(不可变)
    // float originCX;
    // float originCY;
    // float originRadius;

    // 实际的值(可变)
    float cx; // center x of circle
    float cy; // center y of circle
    float radius;

    int color;
    float alpha;

    static Random random = new Random();

    Rect mBound;

    public static Particle generateParticle(int color, Rect bound, Point point) {
        int row = point.y; // 行是高
        int column = point.x; // 列是宽

        Particle particle = new Particle();
        particle.mBound = bound;
        particle.color = color;
        particle.alpha = 1f;

        particle.radius = PART_WH;
        particle.cx = bound.left + PART_WH * column;
        particle.cy = bound.top + PART_WH * row;

        return particle;
    }

    public void advance(float factor) {
        cx = cx + factor * random.nextInt(mBound.width())
                * (random.nextFloat() - 0.5f);
        cy = cy + factor * random.nextInt(mBound.height() / 2);

        radius = radius - factor * random.nextInt(2);

        alpha = (1f - factor) * (1 + random.nextFloat());
    }
}

3.ExplosionAnimator
属性动画,用于动画展示


package com.lgl.animview;

import android.animation.ValueAnimator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.View;

/** * Created by lgl on 16/01/14. */
public class ExplosionAnimator extends ValueAnimator {
    public static final int DEFAULT_DURATION = 1500;
    private Particle[][] mParticles;
    private Paint mPaint;
    private View mContainer;

    public ExplosionAnimator(View view, Bitmap bitmap, Rect bound) {

        mPaint = new Paint();
        mContainer = view;

        setFloatValues(0.0f, 1.0f);
        setDuration(DEFAULT_DURATION);

        mParticles = generateParticles(bitmap, bound);
    }

    private Particle[][] generateParticles(Bitmap bitmap, Rect bound) {
        int w = bound.width();
        int h = bound.height();

        int partW_Count = w / Particle.PART_WH; // 横向个数
        int partH_Count = h / Particle.PART_WH; // 竖向个数

        int bitmap_part_w = bitmap.getWidth() / partW_Count;
        int bitmap_part_h = bitmap.getHeight() / partH_Count;

        Particle[][] particles = new Particle[partH_Count][partW_Count];
        Point point = null;
        for (int row = 0; row < partH_Count; row++) { // 行
            for (int column = 0; column < partW_Count; column++) { // 列
                // 取得当前粒子所在位置的颜色
                int color = bitmap.getPixel(column * bitmap_part_w, row
                        * bitmap_part_h);

                point = new Point(column, row); // x是列,y是行

                particles[row][column] = Particle.generateParticle(color,
                        bound, point);
            }
        }

        return particles;
    }

    public void draw(Canvas canvas) {
        if (!isStarted()) { // 动画结束时停止
            return;
        }
        for (Particle[] particle : mParticles) {
            for (Particle p : particle) {
                p.advance((Float) getAnimatedValue());
                mPaint.setColor(p.color);
                // mPaint.setAlpha((int) (255 * p.alpha)); //只是这样设置,透明色会显示为黑色
                mPaint.setAlpha((int) (Color.alpha(p.color) * p.alpha)); // 这样透明颜色就不是黑色了
                canvas.drawCircle(p.cx, p.cy, p.radius, mPaint);
            }
        }

        mContainer.invalidate();
    }

    @Override
    public void start() {
        super.start();
        mContainer.invalidate();
    }
}

4.ExplosionField
开始执行这个实例的动画了

package com.lgl.animview;

import java.util.ArrayList;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;

/** * Created by lgl on 16/01/14. */
public class ExplosionField extends View {
    private static final String TAG = "ExplosionField";
    private static final Canvas mCanvas = new Canvas();
    private ArrayList<ExplosionAnimator> explosionAnimators;
    private OnClickListener onClickListener;

    public ExplosionField(Context context) {
        super(context);
        init();
    }

    public ExplosionField(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        explosionAnimators = new ArrayList<ExplosionAnimator>();

        attach2Activity((Activity) getContext());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (ExplosionAnimator animator : explosionAnimators) {
            animator.draw(canvas);
        }
    }

    /** * 爆破 * * @param view * 使得该view爆破 */
    public void explode(final View view) {
        Rect rect = new Rect();
        view.getGlobalVisibleRect(rect); // 得到view相对于整个屏幕的坐标
        rect.offset(0, -ParticleUtils.dp2px(25)); // 去掉状态栏高度

        final ExplosionAnimator animator = new ExplosionAnimator(this,
                createBitmapFromView(view), rect);
        explosionAnimators.add(animator);

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                view.animate().alpha(0f).setDuration(150).start();
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                view.animate().alpha(1f).setDuration(150).start();

                // 动画结束时从动画集中移除
                explosionAnimators.remove(animation);
                animation = null;
            }
        });
        animator.start();
    }

    private Bitmap createBitmapFromView(View view) {
        /* * 为什么屏蔽以下代码段? 如果ImageView直接得到位图,那么当它设置背景(backgroud)时,不会读取到背景颜色 */
        // if (view instanceof ImageView) {
        // Drawable drawable = ((ImageView)view).getDrawable();
        // if (drawable != null && drawable instanceof BitmapDrawable) {
        // return ((BitmapDrawable) drawable).getBitmap();
        // }
        // }

        // view.clearFocus(); //不同焦点状态显示的可能不同——(azz:不同就不同有什么关系?)

        Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
                Bitmap.Config.ARGB_8888);

        if (bitmap != null) {
            synchronized (mCanvas) {
                mCanvas.setBitmap(bitmap);
                view.draw(mCanvas);
                mCanvas.setBitmap(null); // 清除引用
            }
        }
        return bitmap;
    }

    /** * 给Activity加上全屏覆盖的ExplosionField */
    private void attach2Activity(Activity activity) {
        ViewGroup rootView = (ViewGroup) activity
                .findViewById(Window.ID_ANDROID_CONTENT);

        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        rootView.addView(this, lp);
    }

    /** * 希望谁有破碎效果,就给谁加Listener * * @param view * 可以是ViewGroup */
    public void addListener(View view) {
        if (view instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) view;
            int count = viewGroup.getChildCount();
            for (int i = 0; i < count; i++) {
                addListener(viewGroup.getChildAt(i));
            }
        } else {
            view.setClickable(true);
            view.setOnClickListener(getOnClickListener());
        }
    }

    private OnClickListener getOnClickListener() {
        if (null == onClickListener) {

            onClickListener = new OnClickListener() {
                @Override
                public void onClick(View v) {
                    ExplosionField.this.explode(v);

                    // view.setOnClickListener(null); // 用过一次就不需要了
                }
            };
        }

        return onClickListener;
    }
}

5.MainActivity
好的,一切准备好了之后我们就可以使用了


package com.lgl.animview;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

    // 实例化粒子动画
    private ExplosionField explosionField;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        explosionField = new ExplosionField(this);
        // 绑定哪个控件哪个控件就有效果,如果需要整个layout,只要绑定根布局的id即可
        explosionField.addListener(findViewById(R.id.iv_round));
    }
}

在xml中我们什么也不用做,好的,让我们来运行一下

你可能感兴趣的:(粒子爆炸,MUI卸载动画)