声明:
根据原文 http://blog.csdn.net/u014608640/article/details/52487653 基础上修改, 模拟碰撞, 可随机颜色, 气泡模糊等
成员变量定义
private static final int MSG_CREATE_BUBBLE =
0;
public static final int MAX_LEVEL =
100;
public static final int MIN_LEVEL =
0;
protected float mWidth;
protected float mHeight;
protected int mColor =
0xFF61d66b;
protected float mTop;
protected float mBottom;
protected Paint mPaint;
protected int mLevel =
100;
private List<Bubble> mBubbles =
new CopyOnWriteArrayList<>();
private Random mRandom =
new Random();
private boolean mStarting =
false;
private Paint mBubblePaint;
private String[] mBubbleColors = {
"#ffec5c",
"#00ccff",
"#ffffff"
};
获取控件宽高
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
onDraw 所有气泡都在这里面绘制
@Override
protected final void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
mTop = mHeight - (
int) (mHeight * (mLevel *
1f / MAX_LEVEL));
mBottom = mHeight;
RectF topRectF =
new RectF(
0,
0, mWidth, mTop);
mPaint.setAlpha(
50);
canvas.drawRect(topRectF, mPaint);
RectF bottomRectF =
new RectF(
0, mTop, mWidth, mBottom);
mPaint.setAlpha(
255);
canvas.drawRect(bottomRectF, mPaint);
drawBubble(canvas);
invalidate();
}
接下来就要气泡的产生过程及绘制
气泡实体类
private class Bubble {
/** 气泡半径 */
private float radius;
/** 上升速度 */
private float speedY;
/** 平移速度 */
private float speedX;
/** 气泡x坐标 */
private float x;
/** 气泡y坐标 */
private float y;
/** 距离顶部消失距离 */
private float removeY;
/** 渐变色 */
private int[] shaderColor;
private int originalColor;
public float getRadius() {
return radius;
}
public void setRadius(
float radius) {
this.radius = radius;
}
public float getX() {
return x;
}
public void setX(
float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setRemoveY(
float y) {
this.removeY = y;
}
public float getRemoveY() {
return removeY;
}
public void setY(
float y) {
this.y = y;
}
public float getSpeedY() {
return speedY;
}
public void setSpeedY(
float speedY) {
this.speedY = speedY;
}
public float getSpeedX() {
return speedX;
}
public void setSpeedX(
float speedX) {
this.speedX = speedX;
}
public void setShaderColor(
int color) {
originalColor = color;
this.shaderColor =
new int[] {
ColorUtil.parseColor(color,
"#cc"),
ColorUtil.parseColor(color,
"#cc"),
ColorUtil.parseColor(color,
"#cc"),
ColorUtil.parseColor(color,
"#aa"),
ColorUtil.parseColor(color,
"#99"),
ColorUtil.parseColor(color,
"#77"),
ColorUtil.parseColor(color,
"#44"),
ColorUtil.parseColor(color,
"#00"),
};
}
public int[]
getShaderColor() {
return this.shaderColor;
}
public int getOriginalColor() {
return originalColor;
}
}
####如何产生气泡呢? 气泡并不是一下子就出来, 而是隔一段时间产生一个, 而这个时间段又不是固定, 需要随机, 可以通过Handler 延迟产生气泡
/**
开始气泡上升动画
*/
@Override
public void startAnim() {
if (!mStarting) {
mStarting =
true;
invalidate();
mHandler.sendEmptyMessage(MSG_CREATE_BUBBLE);
}
}
/**
停止气泡上升动画
*/
@Override
public void stopAnim() {
if (mStarting) {
mStarting =
false;
mHandler.removeMessages(MSG_CREATE_BUBBLE);
mBubbles.clear();
invalidate();
}
}
@Override
public void invalidate() {
if (mStarting) {
super.invalidate();
}
}
创建气泡, 气泡初始配置可根据需要自行设置
private Handler mHandler =
new Handler(secondLooper) {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_CREATE_BUBBLE) {
if (mStarting) {
if (mWidth >
0) {
Bubble bubble =
new Bubble();
int radius = mRandom.nextInt((
int) (mWidth /
10f)) + (
int)(mWidth /
7);
bubble.setRadius(radius);
bubble.setX(mWidth /
2);
bubble.setY(mHeight);
bubble.setSpeedX((mRandom.nextFloat() -
0.5f) *
2.3f);
bubble.setSpeedY(mRandom.nextFloat() *
10 +
1);
bubble.setRemoveY(mRandom.nextInt(radius));
bubble.setShaderColor(ColorUtil.parseColor(mBubbleColors[mRandom.nextInt(mBubbleColors.length)],
"#00"));
mBubbles.add(bubble);
}
mHandler.sendEmptyMessageDelayed(MSG_CREATE_BUBBLE, (
long) ((mRandom.nextInt(
2) +
1) *
300));
}
}
}
};
前方高能: 要绘制气泡了! drawBubble(Canvas canvas)
List<Bubble>
list = mBubbles;
for (Bubble bubble :
list) {
float y = bubble.getY();
float x = bubble.getX();
float speedY = bubble.getSpeedY();
float speedX = bubble.getSpeedX();
float radius = bubble.getRadius();
if (y - bubble.getRemoveY() - speedY <= mTop) {
mBubbles.remove(bubble);
}
else {
if ((x + speedX <= radius) || (x + speedX >= mWidth - radius)) {
speedX = -speedX *
0.8f;
bubble.setSpeedX(speedX);
}
x += speedX;
y -= speedY;
speedY *=
0.99f;
if (speedY <
1) {
speedY =
1;
}
bubble.setX(x);
bubble.setY(y);
bubble.setSpeedY(speedY);
RadialGradient shader =
new RadialGradient(x, y, radius, bubble.getShaderColor(), null, Shader.TileMode.REPEAT);
mBubblePaint.setShader(shader);
canvas.drawCircle(x, y, radius, mBubblePaint);
collision(bubble, x, y, radius);
}
}
气泡碰撞
private void collision(
final Bubble bubble,
final float x,
final float y,
final float radius) {
new Thread(
new Runnable() {
@Override
public void run() {
for (Bubble tempBubble : mBubbles) {
if (tempBubble != bubble) {
float tempX = tempBubble.getX();
float tempY = tempBubble.getY();
float tempRadius = tempBubble.getRadius();
if (isCollisionWithCircle(x, y, tempX, tempY, radius, tempRadius)) {
float r = Math.max(radius, tempRadius) *
1.015f;
float maxRadius = mWidth /
3f;
if (r > maxRadius){
r = maxRadius;
}
Bubble removeBubble, leaveBubble;
if (y < tempY) {
removeBubble = tempBubble;
leaveBubble = bubble;
}
else {
removeBubble = bubble;
leaveBubble = tempBubble;
}
mBubbles.remove(removeBubble);
float tempLeaveSpeedX = leaveBubble.getSpeedX();
float leaveSpeedX = Math.abs(tempLeaveSpeedX);
if (leaveBubble.getX() < removeBubble.getX()) {
leaveSpeedX = -Math.abs(tempLeaveSpeedX);
}
leaveBubble.setRadius(r);
leaveBubble.setSpeedX(leaveSpeedX *
0.9f);
leaveBubble.setSpeedY((removeBubble.getSpeedY() + leaveBubble.getSpeedY()) /
2f);
}
}
}
}
}).start();
}
/**
是否碰撞
*/
private boolean isCollisionWithCircle(
float x1,
float y1,
float x2,
float y2,
float r1,
float r2) {
if (Math.sqrt(Math.pow(x1 - x2,
2) + Math.pow(y1 - y2,
2)) <= (r1 + r2) *
0.85f) {
return true;
}
return false;
}
最后颜色工具类
/**
* Created by zengyan on 2017/3/10.
*/
public class ColorUtil {
/**
* 颜色设置alpha
* @param colorString 颜色值 如: "#ffffff"
* @param alphaString 透明度值 如: "#aa"
* @return
*/
public static int parseColor(String colorString, String alphaString) {
if (colorString.charAt(
0) ==
'#') {
long color = Long.parseLong(colorString.substring(
1),
16);
if (colorString.length() ==
7) {
color = parseColor(color, alphaString);
}
else if (colorString.length() !=
9) {
throw new IllegalArgumentException(
"Unknown color");
}
return (
int)color;
}
throw new IllegalArgumentException(
"Unknown color");
}
/**
* 颜色设置alpha
* @param color 颜色值
* @param alphaString 透明度值 如: "#aa"
* @return
*/
public static int parseColor(
long color, String alphaString) {
if (alphaString.charAt(
0) ==
'#' && alphaString.length() ==
3) {
int alpha = Integer.parseInt(alphaString.substring(
1),
16);
alpha = alpha <<
24;
alpha &=
0x00000000ff000000;
color |= alpha;
}
else {
throw new IllegalArgumentException(
"Unknown alpha");
}
return (
int)color;
}
}
代码基本上就是这么多了, 感谢原代码提供者, 希望对有需要的人有帮助, 后面有时间会研究气泡融合的效果, 目前思路为: 气泡碰撞时, 将要被融合的气泡放进 融合气泡内部list, 待canvas画融合气泡连同内部被融合的list一块画使用贝塞尔曲线达到融合效果.