Android 充电气泡动画
追忆似水年华 · 894浏览 · 发布于2019-11-01
效果图:
代码部分
BubbleView.java
/** * 气泡自定义控件 * 思路: * 1,定义 Bubble 类; * 2,随机生成 Bubble 对象,存放于 List 中; * 3,刷新 List 中的数据: 边界控制; * 4,刷新 UI。 * * @author wangzhichao * @date 2019/10/30 */ public class BubbleView extends View { private static final String TAG = BubbleView.class.getSimpleName(); private HandlerThread handlerThread; private WeakHandler weakHandler; private static final int MESSAGE_UPDATE = 1; private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); private int bubbleNumLimit; private float minBubbleSpeedX; private float maxBubbleSpeedX; private float minBubbleSpeedY; private float maxBubbleSpeedY; private float minBubbleRadius; private float maxBubbleRadius; private float bubbleCreateLatch; private int width; private int height; private int defaultWidth = (int) dp2px(10); private int defaultHeight = (int) dp2px(20); public BubbleView(Context context) { this(context, null); } public BubbleView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BubbleView); minBubbleSpeedX = ta.getDimensionPixelSize(R.styleable.BubbleView_bvMinBubbleSpeedX, (int) dp2px(1f)); maxBubbleSpeedX = ta.getDimensionPixelSize(R.styleable.BubbleView_bvMaxBubbleSpeedX, (int) dp2px(2)); minBubbleSpeedY = ta.getDimensionPixelSize(R.styleable.BubbleView_bvMinBubbleSpeedY, (int) dp2px(2)); maxBubbleSpeedY = ta.getDimensionPixelSize(R.styleable.BubbleView_bvMaxBubbleSpeedY, (int) dp2px(4)); minBubbleRadius = ta.getDimensionPixelSize(R.styleable.BubbleView_bvMinBubbleRadius, (int) dp2px(1)); maxBubbleRadius = ta.getDimensionPixelSize(R.styleable.BubbleView_bvMaxBubbleRadius, (int) dp2px(4)); bubbleNumLimit = ta.getInt(R.styleable.BubbleView_bvBubbleNumLimit, 10); bubbleCreateLatch = ta.getFloat(R.styleable.BubbleView_bvBubbleCreateLatch, 0.5f); int color = ta.getColor(R.styleable.BubbleView_bvBubbleColor, getResources().getColor(R.color.white)); int alpha = ta.getInt(R.styleable.BubbleView_bvBubbleAlpha, 128); ta.recycle(); handlerThread = new HandlerThread(TAG); paint.setColor(color); paint.setAlpha(alpha); paint.setStyle(Paint.Style.FILL); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); handlerThread.start(); Looper looper = handlerThread.getLooper(); weakHandler = new WeakHandler(looper, msg -> { if (msg.what == MESSAGE_UPDATE) { tryCreateBubbles(); updateBubbles(); postInvalidate(); } return true; }); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); weakHandler.removeCallbacksAndMessages(null); handlerThread.quit(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); width = getWidth() - getPaddingLeft() - getPaddingRight(); height = getHeight() - getPaddingTop() - getPaddingBottom(); drawBubbles(canvas); weakHandler.sendEmptyMessage(MESSAGE_UPDATE); } private void drawBubbles(Canvas canvas) { for (Bubble bubble : bubbles) { canvas.drawCircle(bubble.getCenterX(), bubble.getCenterY(), bubble.getRadius(), paint); } } private void updateBubbles() { Iterator<Bubble> iterator = bubbles.iterator(); while (iterator.hasNext()) { Bubble bubble = iterator.next(); bubble.setCenterX(bubble.getCenterX() + bubble.getSpeedX()); bubble.setCenterY(bubble.getCenterY() - bubble.getSpeedY()); if (isBubbleTouchTop(bubble)) { iterator.remove(); } else if (isBubbleTouchLeft(bubble)) { bubble.setSpeedX(-bubble.getSpeedX()); bubble.setCenterX(bubble.getRadius()); } else if (isBubbleTouchRight(bubble)) { bubble.setSpeedX(-bubble.getSpeedX()); bubble.setCenterX(width - bubble.getRadius()); } } } private boolean isBubbleTouchLeft(Bubble bubble) { return bubble.getCenterX() - bubble.getRadius() <= 0; } private boolean isBubbleTouchRight(Bubble bubble) { return bubble.getCenterX() + bubble.getRadius() >= width; } private boolean isBubbleTouchTop(Bubble bubble) { return bubble.getCenterY() - bubble.getRadius() <= 0; } private List<Bubble> bubbles = new ArrayList<>(); private void tryCreateBubbles() { if (bubbles.size() >= bubbleNumLimit) { return; } if (random.nextFloat() < bubbleCreateLatch) { return; } bubbles.add(createBubble()); } private Bubble createBubble() { Bubble bubble = new Bubble(); bubble.setRadius(getRandomRadius()); bubble.setSpeedX(getRandomSpeedX()); bubble.setSpeedY(getRandomSpeedY()); bubble.setCenterX(width / 2f); bubble.setCenterY(height + bubble.getRadius()); return bubble; } private Random random = new Random(); private float getRandomSpeedX() { float value = minBubbleSpeedX + random.nextFloat() * (maxBubbleSpeedX - minBubbleSpeedX); if (random.nextBoolean()) { return value; } else { return -value; } } private float getRandomSpeedY() { return minBubbleSpeedY + random.nextFloat() * (maxBubbleSpeedY - minBubbleSpeedY); } private float getRandomRadius() { return minBubbleRadius + random.nextFloat() * (maxBubbleRadius - minBubbleRadius); } private int measureWidth(int widthMeasureSpec) { int mode = MeasureSpec.getMode(widthMeasureSpec); int size = MeasureSpec.getSize(widthMeasureSpec); int result; if (mode == MeasureSpec.EXACTLY) { result = size; } else { result = defaultWidth; if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } private int measureHeight(int heightMeasureSpec) { int mode = MeasureSpec.getMode(heightMeasureSpec); int size = MeasureSpec.getSize(heightMeasureSpec); int result; if (mode == MeasureSpec.EXACTLY) { result = size; } else { result = defaultHeight; if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } /** * 气泡 */ class Bubble { /** * 气泡的半径 */ private float radius; /** * 气泡 x 向的移动速度 */ private float speedX; /** * 气泡 y 向的移动速度 */ private float speedY; /** * 气泡的中心 x 坐标 */ private float centerX; /** * 气泡的中心 y 坐标 */ private float centerY; public float getRadius() { return radius; } public void setRadius(float radius) { this.radius = radius; } public float getSpeedX() { return speedX; } public void setSpeedX(float speedX) { this.speedX = speedX; } public float getSpeedY() { return speedY; } public void setSpeedY(float speedY) { this.speedY = speedY; } public float getCenterX() { return centerX; } public void setCenterX(float centerX) { this.centerX = centerX; } public float getCenterY() { return centerY; } public void setCenterY(float centerY) { this.centerY = centerY; } } private float dp2px(float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics()); } }
自定义属性:
<declare-styleable name="BubbleView"> <attr name="bvMinBubbleSpeedX" format="dimension" /> <attr name="bvMaxBubbleSpeedX" format="dimension" /> <attr name="bvMinBubbleSpeedY" format="dimension" /> <attr name="bvMaxBubbleSpeedY" format="dimension" /> <attr name="bvMinBubbleRadius" format="dimension" /> <attr name="bvMaxBubbleRadius" format="dimension" /> <attr name="bvBubbleNumLimit" format="integer" /> <attr name="bvBubbleColor" format="color" /> <attr name="bvBubbleAlpha" format="integer" /> <attr name="bvBubbleCreateLatch" format="float" /> </declare-styleable>
最后
代码还是有一些不足,大家多提宝贵意见。
相关推荐
android下vulkan与opengles纹理互通
talkchan · 1176浏览 · 2020-11-23 10:37:39
Android 使用RecyclerView实现轮播图
奔跑的男人 · 2175浏览 · 2019-05-09 17:11:13
微软发布新命令行工具 Windows Terminal
吴振华 · 869浏览 · 2019-05-09 17:15:04
在华为写了十几年代码,我为什么还没有被拿去“祭天”
追忆似水年华 · 1201浏览 · 2019-05-09 17:22:20
android 通过修改图片像素实现CircleImageView
吴振华 · 1127浏览 · 2019-05-09 22:26:56
分类专栏
最新发布
最热排行
0评论