需要用到自定义动画,工具类如下:
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();
}
}
public class ExplosionField extends View{
private static final String TAG = “ExplosionField”;
private static final Canvas mCanvas = new Canvas();
private ArrayList 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, -Utils.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;
}
}
/*
* 爆破粒子
*/
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());
}
}
public class Utils {
/**
* 密度
*/
public static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;
public static int dp2px(int dp) {
return Math.round(dp * DENSITY);
}
}
//爆破效果
//实现爆炸动画只需实例化工具类即可,Layout指要有爆炸效果的布局
ExplosionField explosionField = new ExplosionField(this);
explosionField.addListener(Layout);