在线直播源码,自定义气泡效果(BubbleView)

在线直播源码,自定义气泡效果(BubbleView)

代码如下:

 

1
<br>package com.example.myapplication;<br>import android.content.Context;<br>import android.graphics.BlurMaskFilter;<br>import android.graphics.Canvas;<br>import android.graphics.Color;<br>import android.graphics.Paint;<br>import android.graphics.RectF;<br>import android.util.AttributeSet;<br>import android.util.Log;<br>import android.util.TypedValue;<br>import android.view.View;<br>import androidx.annotation.Nullable;<br>import java.util.ArrayList;<br>import java.util.List;<br>import java.util.Random;<br>public class BubbleView extends View {<br>    private int mBubbleMaxRadius = 15;          // 气泡最大半径 px<br>    private int mBubbleMinRadius = 8;           // 气泡最小半径 px<br>    private int mBubbleMaxSize = 50;            // 气泡数量<br>    private int mBubbleRefreshTime = 50;        // 刷新间隔<br>    private int mBubbleMaxSpeedY = 2;           // 气泡速度<br>    private int mBubbleMaxSpeedX = 4;           // 气泡速度<br>    private int mBubbleAlpha = 128;             // 气泡画笔<br>    private float mContentWidth;                 // 瓶子宽度<br>    private float mContentHeight;                // 瓶子高度<br>    private RectF mContentRectF;                // 实际可用内容区域<br>    private Paint mBubblePaint;                 // 气泡画笔<br>    public BubbleView(Context context) {<br>        this(context, null);<br>    }<br>    public BubbleView(Context context, @Nullable AttributeSet attrs) {<br>        this(context, attrs, 0);<br>    }<br>    public BubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {<br>        super(context, attrs, defStyleAttr);<br>        mContentWidth = dp2px(130);<br>        mContentHeight = dp2px(260);<br>        mBubblePaint = new Paint();<br>        mBubblePaint.setColor(Color.GREEN);<br>        mBubblePaint.setAlpha(mBubbleAlpha);<br>    }<br>    @Override<br>    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {<br>        super.onMeasure(widthMeasureSpec, heightMeasureSpec);<br>        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);<br>        int widthSize = MeasureSpec.getSize(widthMeasureSpec);<br>        int heightSize = MeasureSpec.getSize(heightMeasureSpec);<br>        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);<br>        int width;<br>        int height;<br>        if (widthSpecMode == MeasureSpec.EXACTLY || widthSpecMode == MeasureSpec.AT_MOST) {<br>            width = widthSize;<br>            mContentWidth = width;<br>        } else {<br>            width = (int) mContentWidth;<br>        }<br>        if (heightSpecMode == MeasureSpec.EXACTLY || heightSpecMode == MeasureSpec.AT_MOST) {<br>            height = heightSize;<br>            mContentHeight = height;<br>        } else {<br>            height = (int) mContentHeight;<br>        }<br>        setMeasuredDimension(width, height);<br>    }<br>    @Override<br>    protected void onSizeChanged(int w, int h, int oldw, int oldh) {<br>        super.onSizeChanged(w, h, oldw, oldh);<br>        mContentRectF = new RectF(getPaddingLeft(), getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom());<br>    }<br>    @Override<br>    protected void onDraw(Canvas canvas) {<br>        super.onDraw(canvas);<br>        drawBubble(canvas);<br>    }<br>    @Override<br>    protected void onAttachedToWindow() {<br>        super.onAttachedToWindow();<br>        startBubbleSync();<br>    }<br>    @Override<br>    protected void onDetachedFromWindow() {<br>        super.onDetachedFromWindow();<br>        stopBubbleSync();<br>    }<br>    private static class Bubble {<br>        int radius;     // 气泡半径<br>        float speedY;   // 上升速度<br>        float speedX;   // 平移速度<br>        float x;        // 气泡x坐标<br>        float y;        // 气泡y坐标<br>    }<br>    private ArrayList<Bubble> mBubbles = new ArrayList<>();<br>    private Random random = new Random();<br>    private Thread mBubbleThread;<br>    // 开始气泡线程<br>    private void startBubbleSync() {<br>        stopBubbleSync();<br>        mBubbleThread = new Thread() {<br>            public void run() {<br>                while (true) {<br>                    try {<br>                        Thread.sleep(mBubbleRefreshTime);<br>                        tryCreateBubble();<br>                        refreshBubbles();<br>                        postInvalidate();<br>                    } catch (InterruptedException e) {<br>                        break;<br>                    }<br>                }<br>            }<br>        };<br>        mBubbleThread.start();<br>    }<br>    // 停止气泡线程<br>    private void stopBubbleSync() {<br>        if (null == mBubbleThread) return;<br>        mBubbleThread.interrupt();<br>        mBubbleThread = null;<br>    }<br>    // 绘制气泡<br>    private void drawBubble(Canvas canvas) {<br>        List<Bubble> list = new ArrayList<>(mBubbles);<br>        for (Bubble bubble : list) {<br>            if (null == bubble) continue;<br>            canvas.drawCircle(bubble.x, bubble.y,<br>                    bubble.radius, mBubblePaint);<br>        }<br>    }<br>    // 创建气泡<br>    private void tryCreateBubble() {<br>        if (null == mContentRectF) return;<br>        if (mBubbles.size() >= mBubbleMaxSize) {<br>            return;<br>        }<br>        if (random.nextFloat() < 0.95) {<br>            return;<br>        }<br>        Bubble bubble = new Bubble();<br>        int radius = random.nextInt(mBubbleMaxRadius - mBubbleMinRadius);<br>        radius += mBubbleMinRadius;<br>        float speedX = 0.5f * mBubbleMaxSpeedX;<br>//        while (speedX < 1) {<br>//            speedX = random.nextFloat() * mBubbleMaxSpeedX;<br>//        }<br>        bubble.radius = radius;<br>        bubble.speedX = speedX;<br>        bubble.x = mContentRectF.left;<br>        bubble.y = mContentRectF.centerY();<br>        float speedY = random.nextFloat() - 0.5f;<br>        while (speedY == 0) {<br>            speedY = random.nextFloat() - 0.5f;<br>        }<br>        bubble.speedY = speedY * 2;<br>        mBubblePaint.setMaskFilter(new BlurMaskFilter(radius, BlurMaskFilter.Blur.SOLID));<br>        mBubbles.add(bubble);<br>    }<br>    // 刷新气泡位置,超出的气泡进行移除<br>    private void refreshBubbles() {<br>        List<Bubble> list = new ArrayList<>(mBubbles);<br>        for (Bubble bubble : list) {<br>            if (bubble.x + bubble.speedX >= mContentRectF.right + bubble.radius) {<br>                mBubbles.remove(bubble);<br>            } else {<br>                int i = mBubbles.indexOf(bubble);<br>                if (bubble.y + bubble.speedY <= mContentRectF.top + bubble.radius) {<br>                    bubble.y = mContentRectF.top + bubble.radius;<br>                } else {<br>                    bubble.y = Math.min(bubble.y + bubble.speedY, mContentRectF.bottom - bubble.radius);<br>                }<br>                bubble.x = bubble.x + bubble.speedX;<br>                mBubbles.set(i, bubble);<br>            }<br>        }<br>    }<br>    private float dp2px(float dpValue) {<br>        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics());<br>    }<br>}

目前为自定义属性,布局文件中直接引用即可。

 

1
<br>  <com.example.myapplication.BubbleView<br>        android:layout_width="300dp"<br>        android:layout_height="100dp"/>

 

以上就是 在线直播源码,自定义气泡效果(BubbleView),更多内容欢迎关注之后的文章

 

posted @   云豹科技-苏凌霄  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示