开源 java android app 开发(十四)自定义绘图控件--波形图

文章的目的为了记录使用java 进行android app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

相关链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

开源 java android app 开发(十三)自定义绘图控件--游戏摇杆

开源 java android app 开发(十四)自定义绘图控件--波形图

开源 java android app 开发(十五)自定义绘图控件--仪表盘

开源 java android app 开发(十六)自定义绘图控件--圆环

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

本章节主要内容是:自定义的波形图控件的使用,主活动随机产生多条曲线。

1.代码分析

2.所有源码

3.效果图

一、代码分析

WaveView自定义View详细函数分析

  1. 构造函数和初始化

init(AttributeSet attrs) - 核心初始化函数

复制代码
private void init(AttributeSet attrs) {
    waveDataList = new ArrayList<>();  // 初始化波形数据列表
    
    // 设置深蓝色科幻风格背景
    setBackgroundColor(backgroundColor);
    
    // 初始化四种不同的画笔
    initAxisPaint();     // 坐标轴画笔
    initGridPaint();     // 网格画笔  
    initTextPaint();     // 文字画笔
    initGlowPaint();     // 发光效果画笔
    
    // 设置默认坐标轴尺寸
    xAxisSize = 800;     // X轴宽度
    yAxisSize = 400;     // Y轴高度
    
    // 启用硬件加速提升性能
    setLayerType(LAYER_TYPE_HARDWARE, null);
}

画笔初始化细节

坐标轴画笔:

颜色:半透明青色 Color.argb(180, 0, 255, 255)

线宽:3像素

样式:描边 Style.STROKE

抗锯齿:开启

网格画笔:

颜色:更透明的青色 Color.argb(80, 0, 255, 255)

线宽:1像素(比坐标轴细)

文字画笔:

字体大小:28sp

对齐方式:居中 Align.CENTER

发光画笔:

特殊效果:阴影层 setShadowLayer(15, 0, 0, Color.argb(150, 0, 255, 255))

阴影半径15像素,产生光晕效果

  1. 数据管理函数

addWaveData(String name, int color) - 添加波形通道

复制代码
public void addWaveData(String name, int color) {
    WaveData waveData = new WaveData(name, color);  // 创建波形数据对象
    waveDataList.add(waveData);                     // 添加到列表
    // 注意:这里没有调用invalidate(),因为只是添加通道还没有数据
}
addDataToWave(String name, float value) - 添加数据点
java
public void addDataToWave(String name, float value) {
    for (WaveData waveData : waveDataList) {
        if (waveData.getName().equals(name)) {
            waveData.addData(value);  // 添加数据
            
            // FIFO管理:超过200个点移除最旧的数据
            if (waveData.getData().size() > maxDataPoints) {
                waveData.getData().remove(0);  // 移除第一个元素
            }
            break;
        }
    }
    invalidate();  // 触发重绘
}

数据流管理:

查找对应名称的波形通道

添加新数据点

维护固定长度队列(200点)

自动触发界面更新

  1. 绘制函数详细分析

onDraw(Canvas canvas) - 主绘制流程

复制代码
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);  // 调用父类绘制(背景色)
    
    // 绘制顺序:从底层到顶层
    if (showGrid) {
        drawGrid(canvas);      // 1. 网格(最底层)
    }
    drawAxis(canvas);          // 2. 坐标轴
    drawWaves(canvas);         // 3. 波形数据(主要内容)
    drawLegend(canvas);        // 4. 图例(覆盖在波形上)
    drawBorder(canvas);        // 5. 边框(最顶层)
}
drawGrid(Canvas canvas) - 网格绘制
java
private void drawGrid(Canvas canvas) {
    float startX = 50;                    // 网格起始X坐标
    float startY = getHeight() - 50;      // 网格起始Y坐标(底部向上50px)
    float endX = startX + xAxisSize;      // 网格结束X坐标
    float endY = startY - yAxisSize;      // 网格结束Y坐标
    
    // 水平网格线:gridDensity+1条线(包含边界)
    for (int i = 0; i <= gridDensity; i++) {
        float y = startY - (i * yAxisSize / gridDensity);  // 等分Y轴
        canvas.drawLine(startX, y, endX, y, gridPaint);    // 绘制水平线
    }
    
    // 垂直网格线:2倍密度,更密的纵向网格
    for (int i = 0; i <= gridDensity * 2; i++) {
        float x = startX + (i * xAxisSize / (gridDensity * 2));
        canvas.drawLine(x, startY, x, endY, gridPaint);
    }
}

网格特点:

水平线:按gridDensity等分(默认10等分)

垂直线:双倍密度,更细的纵向分割

网格区域:固定位置,距离左边和底部各50像素

drawAxis(Canvas canvas) - 坐标轴绘制

复制代码
private void drawAxis(Canvas canvas) {
    float startX = 50;                    // 坐标原点X
    float startY = getHeight() - 50;      // 坐标原点Y
    float endX = startX + xAxisSize;      // X轴终点
    float endY = startY - yAxisSize;      // Y轴终点
    
    // 绘制X轴和Y轴主线
    canvas.drawLine(startX, startY, endX, startY, axisPaint);  // X轴
    canvas.drawLine(startX, startY, startX, endY, axisPaint);  // Y轴
    
    // 绘制箭头(简化版,只是延长线)
    drawArrow(canvas, endX, startY, endX + 15, startY);  // X轴箭头
    drawArrow(canvas, startX, endY, startX, endY - 15);  // Y轴箭头
    
    // X轴刻度(11个刻度:0-10)
    for (int i = 0; i <= 10; i++) {
        float x = startX + (i * xAxisSize / 10);
        canvas.drawLine(x, startY, x, startY - 8, axisPaint);  // 刻度线
        canvas.drawText(String.valueOf(i), x, startY + 25, textPaint);  // 刻度值
    }
    
    // Y轴刻度(6个刻度:0-5)
    for (int i = 0; i <= 5; i++) {
        float y = startY - (i * yAxisSize / 5);
        canvas.drawLine(startX, y, startX + 8, y, axisPaint);
        canvas.drawText(String.valueOf(i), startX - 20, y + 10, textPaint);
    }
    
    // 坐标轴标签(带旋转效果)
    canvas.drawText("时间 (s)", startX + xAxisSize / 2, startY + 50, textPaint);
    canvas.save();  // 保存画布状态
    canvas.rotate(-90, startX - 40, startY - yAxisSize / 2);  // 旋转-90度
    canvas.drawText("幅度 (V)", startX - 40, startY - yAxisSize / 2, textPaint);
    canvas.restore();  // 恢复画布状态
}

坐标轴特性:

固定刻度数量:X轴11个,Y轴6个

Y轴标签通过旋转实现垂直文字

使用save()/restore()保护画布状态

drawWaves(Canvas canvas) - 核心波形绘制

复制代码
private void drawWaves(Canvas canvas) {
    if (waveDataList.isEmpty()) return;
    
    float startX = 50;                    // 波形起始X
    float startY = getHeight() - 50;      // 波形起始Y(坐标原点)
    float xStep = xAxisSize / (maxDataPoints - 1);  // X轴步进(每个数据点间距)
    
    for (WaveData waveData : waveDataList) {
        List<Float> data = waveData.getData();
        if (data.size() < 2) continue;    // 至少需要2个点才能画线
        
        // 1. 绘制发光效果(底层)
        if (showGlowEffect) {
            drawGlowEffect(canvas, waveData, startX, startY, xStep);
        }
        
        // 2. 绘制渐变填充(中层)
        drawGradientFill(canvas, waveData, startX, startY, xStep);
        
        // 3. 绘制主波形线(上层)
        drawMainWaveLine(canvas, waveData, startX, startY, xStep);
        
        // 4. 绘制数据点(可选)
        if (data.size() < 50) {
            drawDataPoints(canvas, waveData, startX, startY, xStep);
        }
    }
}

发光效果绘制

复制代码
// 简化版的发光效果实现
Path glowPath = new Path();
glowPath.moveTo(startX, startY - (data.get(0) * yAxisSize / 5));  // 移动到第一个点

for (int i = 1; i < data.size(); i++) {
    float x = startX + (i * xStep);
    float y = startY - (data.get(i) * yAxisSize / 5);  // 数据映射到坐标
    glowPath.lineTo(x, y);  // 连线到下一个点
}

// 使用半透明的宽线条产生发光效果
glowPaint.setAlpha(100);  // 半透明
glowPaint.setStrokeWidth(5);  // 比主线条粗
canvas.drawPath(glowPath, glowPaint);
渐变填充绘制
java
Path fillPath = new Path();
fillPath.moveTo(startX, startY);  // 从坐标原点开始
fillPath.lineTo(startX, startY - (data.get(0) * yAxisSize / 5));  // 到第一个数据点

// 连接所有数据点
for (int i = 1; i < data.size(); i++) {
    float x = startX + (i * xStep);
    float y = startY - (data.get(i) * yAxisSize / 5);
    fillPath.lineTo(x, y);
}

// 闭合路径:从最后一个点回到坐标原点
fillPath.lineTo(startX + (data.size() - 1) * xStep, startY);
fillPath.close();  // 形成闭合区域

// 创建从上到下的渐变
LinearGradient gradient = new LinearGradient(
    0, startY - yAxisSize,  // 渐变起点(顶部)
    0, startY,              // 渐变终点(底部)
    Color.argb(80, r, g, b),  // 顶部颜色(较深)
    Color.argb(20, r, g, b),  // 底部颜色(较浅)
    Shader.TileMode.CLAMP
);

数据映射公式:

复制代码
// 将数据值映射到屏幕坐标
float y = startY - (dataValue * yAxisSize / 5);
dataValue:原始数据值(0-5范围)

yAxisSize / 5:每个单位对应的像素数

startY - ...:因为屏幕坐标系Y轴向下,需要取反

drawLegend(Canvas canvas) - 图例绘制
java
private void drawLegend(Canvas canvas) {
    float startX = 60 + xAxisSize;        // 图例在波形区域右侧
    float startY = getHeight() - 50 - yAxisSize + 30;  // 与波形顶部对齐
    
    // 绘制半透明背景
    Paint legendBgPaint = new Paint();
    legendBgPaint.setColor(Color.argb(150, 0, 30, 60));  // 深蓝色半透明背景
    canvas.drawRoundRect(startX - 10, startY - 10, 
                        startX + 180, startY + waveDataList.size() * 40 + 20, 
                        10, 10, legendBgPaint);  // 圆角矩形
    
    // 绘制每个波形的图例项
    for (int i = 0; i < waveDataList.size(); i++) {
        WaveData waveData = waveDataList.get(i);
        
        // 颜色方块
        canvas.drawRect(startX, startY + (i * 40), 
                       startX + 20, startY + (i * 40) + 20, 
                       rectPaint);
        
        // 波形名称
        canvas.drawText(waveData.getName(), 
                       startX + 100, startY + (i * 40) + 15, 
                       textPaint);
    }
}
  1. 辅助函数

配置函数族

java

复制代码
public void setAxisSize(float xAxisSize, float yAxisSize) {
    this.xAxisSize = xAxisSize;
    this.yAxisSize = yAxisSize;
    invalidate();  // 尺寸改变后立即重绘
}

public void setGridDensity(int density) {
    this.gridDensity = density;
    invalidate();  // 网格密度改变后重绘
}

public void setShowGrid(boolean show) {
    this.showGrid = show;
    invalidate();  // 显示状态改变后重绘
}

设计模式:所有改变显示状态的函数都调用invalidate()触发界面更新。

  1. 性能优化特性

硬件加速:setLayerType(LAYER_TYPE_HARDWARE, null)

数据量控制:固定200个数据点,避免内存无限增长

条件绘制:数据点少于50时才绘制点状标记

路径绘制:使用Path而非多次drawLine提高效率

  1. 坐标系统总结

text

(0,0) ┌────────────────────────────────────────┐

│ Wave View │

│ ┌─────────────────┐ │

│ │ │ 图例区域 │

│ │ 波形区域 │ ┌──────┐ │

│ │ │ │信号1│ │

│ │ │ │信号2│ │

│ └─────────────────┘ └──────┘ │

│ │

└────────────────────────────────────────┘ (width,height)

波形区域坐标:

起点:(50, height-50)

尺寸:800×400 像素

数据范围:X轴0-10秒,Y轴0-5伏特

这个自定义View设计完整,功能丰富,具有良好的可扩展性和性能优化。

二、所有源码

源码总共3部分

1.waveview.java源码

复制代码
package com.example.wave;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class WaveView extends View {
    private List<WaveData> waveDataList;
    private Paint axisPaint;
    private Paint gridPaint;
    private Paint textPaint;
    private Paint glowPaint;
    private float xAxisSize;
    private float yAxisSize;
    private int maxDataPoints = 200;
    private int gridDensity = 10;
    private boolean showGrid = true;
    private boolean showGlowEffect = true;

    // 科幻风格颜色
    private int gridColor = Color.argb(80, 0, 255, 255); // 半透明青色网格
    private int axisColor = Color.argb(180, 0, 255, 255); // 青色坐标轴
    private int backgroundColor = Color.argb(255, 10, 20, 40); // 深蓝色背景
    private int textColor = Color.argb(200, 0, 255, 255); // 青色文字

    public WaveView(Context context) {
        super(context);
        init(null);
    }

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

    public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        waveDataList = new ArrayList<>();

        // 设置背景色
        setBackgroundColor(backgroundColor);

        // 初始化坐标轴画笔
        axisPaint = new Paint();
        axisPaint.setColor(axisColor);
        axisPaint.setStrokeWidth(3);
        axisPaint.setStyle(Paint.Style.STROKE);
        axisPaint.setAntiAlias(true);

        // 初始化网格画笔
        gridPaint = new Paint();
        gridPaint.setColor(gridColor);
        gridPaint.setStrokeWidth(1);
        gridPaint.setStyle(Paint.Style.STROKE);
        gridPaint.setAntiAlias(true);

        // 初始化文字画笔
        textPaint = new Paint();
        textPaint.setColor(textColor);
        textPaint.setTextSize(28);
        textPaint.setAntiAlias(true);
        textPaint.setTextAlign(Paint.Align.CENTER);

        // 初始化发光效果画笔
        glowPaint = new Paint();
        glowPaint.setStrokeWidth(4);
        glowPaint.setStyle(Paint.Style.STROKE);
        glowPaint.setAntiAlias(true);
        glowPaint.setShadowLayer(15, 0, 0, Color.argb(150, 0, 255, 255));

        // 默认坐标轴大小
        xAxisSize = 800;
        yAxisSize = 400;

        // 启用硬件加速以获得更好的性能
        setLayerType(LAYER_TYPE_HARDWARE, null);
    }

    public void setAxisSize(float xAxisSize, float yAxisSize) {
        this.xAxisSize = xAxisSize;
        this.yAxisSize = yAxisSize;
        invalidate();
    }

    public void setGridDensity(int density) {
        this.gridDensity = density;
        invalidate();
    }

    public void setShowGrid(boolean show) {
        this.showGrid = show;
        invalidate();
    }

    public void setShowGlowEffect(boolean show) {
        this.showGlowEffect = show;
        invalidate();
    }

    public void addWaveData(String name, int color) {
        WaveData waveData = new WaveData(name, color);
        waveDataList.add(waveData);
    }

    public void addDataToWave(String name, float value) {
        for (WaveData waveData : waveDataList) {
            if (waveData.getName().equals(name)) {
                waveData.addData(value);
                if (waveData.getData().size() > maxDataPoints) {
                    waveData.getData().remove(0);
                }
                break;
            }
        }
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制网格
        if (showGrid) {
            drawGrid(canvas);
        }

        // 绘制坐标轴
        drawAxis(canvas);

        // 绘制波形
        drawWaves(canvas);

        // 绘制图例
        drawLegend(canvas);

        // 绘制边框效果
        drawBorder(canvas);
    }

    private void drawGrid(Canvas canvas) {
        float startX = 50;
        float startY = getHeight() - 50;
        float endX = startX + xAxisSize;
        float endY = startY - yAxisSize;

        // 绘制水平网格线
        for (int i = 0; i <= gridDensity; i++) {
            float y = startY - (i * yAxisSize / gridDensity);
            canvas.drawLine(startX, y, endX, y, gridPaint);
        }

        // 绘制垂直网格线
        for (int i = 0; i <= gridDensity * 2; i++) {
            float x = startX + (i * xAxisSize / (gridDensity * 2));
            canvas.drawLine(x, startY, x, endY, gridPaint);
        }
    }

    private void drawAxis(Canvas canvas) {
        float startX = 50;
        float startY = getHeight() - 50;
        float endX = startX + xAxisSize;
        float endY = startY - yAxisSize;

        // 绘制X轴
        canvas.drawLine(startX, startY, endX, startY, axisPaint);
        // 绘制Y轴
        canvas.drawLine(startX, startY, startX, endY, axisPaint);

        // 绘制箭头
        drawArrow(canvas, endX, startY, endX + 15, startY); // X轴箭头
        drawArrow(canvas, startX, endY, startX, endY - 15); // Y轴箭头

        // 绘制刻度
        for (int i = 0; i <= 10; i++) {
            float x = startX + (i * xAxisSize / 10);
            canvas.drawLine(x, startY, x, startY - 8, axisPaint);
            canvas.drawText(String.valueOf(i), x, startY + 25, textPaint);
        }

        for (int i = 0; i <= 5; i++) {
            float y = startY - (i * yAxisSize / 5);
            canvas.drawLine(startX, y, startX + 8, y, axisPaint);
            canvas.drawText(String.valueOf(i), startX - 20, y + 10, textPaint);
        }

        // 绘制坐标轴标签
        canvas.drawText("时间 (s)", startX + xAxisSize / 2, startY + 50, textPaint);
        canvas.save();
        canvas.rotate(-90, startX - 40, startY - yAxisSize / 2);
        canvas.drawText("幅度 (V)", startX - 40, startY - yAxisSize / 2, textPaint);
        canvas.restore();
    }

    private void drawArrow(Canvas canvas, float x1, float y1, float x2, float y2) {
        canvas.drawLine(x1, y1, x2, y2, axisPaint);
    }

    private void drawWaves(Canvas canvas) {
        if (waveDataList.isEmpty()) return;

        float startX = 50;
        float startY = getHeight() - 50;
        float xStep = xAxisSize / (maxDataPoints - 1);

        for (WaveData waveData : waveDataList) {
            List<Float> data = waveData.getData();
            if (data.size() < 2) continue;

            // 绘制主波形线
            Paint mainPaint = new Paint();
            mainPaint.setColor(waveData.getColor());
            mainPaint.setStrokeWidth(3);
            mainPaint.setStyle(Paint.Style.STROKE);
            mainPaint.setAntiAlias(true);

            // 绘制发光效果
            if (showGlowEffect) {
                Paint glowPaint = new Paint();
                glowPaint.setColor(waveData.getColor());
                glowPaint.setStrokeWidth(5);
                glowPaint.setStyle(Paint.Style.STROKE);
                glowPaint.setAlpha(100);
                glowPaint.setAntiAlias(true);

                Path glowPath = new Path();
                glowPath.moveTo(startX, startY - (data.get(0) * yAxisSize / 5));

                for (int i = 1; i < data.size(); i++) {
                    float x = startX + (i * xStep);
                    float y = startY - (data.get(i) * yAxisSize / 5);
                    glowPath.lineTo(x, y);
                }

                canvas.drawPath(glowPath, glowPaint);
            }

            // 绘制渐变填充效果
            Path fillPath = new Path();
            fillPath.moveTo(startX, startY);
            fillPath.lineTo(startX, startY - (data.get(0) * yAxisSize / 5));

            for (int i = 1; i < data.size(); i++) {
                float x = startX + (i * xStep);
                float y = startY - (data.get(i) * yAxisSize / 5);
                fillPath.lineTo(x, y);
            }

            fillPath.lineTo(startX + (data.size() - 1) * xStep, startY);
            fillPath.close();

            Paint fillPaint = new Paint();
            fillPaint.setStyle(Paint.Style.FILL);
            fillPaint.setShader(new LinearGradient(
                    0, startY - yAxisSize,
                    0, startY,
                    Color.argb(80, Color.red(waveData.getColor()),
                            Color.green(waveData.getColor()),
                            Color.blue(waveData.getColor())),
                    Color.argb(20, Color.red(waveData.getColor()),
                            Color.green(waveData.getColor()),
                            Color.blue(waveData.getColor())),
                    Shader.TileMode.CLAMP
            ));

            canvas.drawPath(fillPath, fillPaint);

            // 绘制主波形线
            Path mainPath = new Path();
            mainPath.moveTo(startX, startY - (data.get(0) * yAxisSize / 5));

            for (int i = 1; i < data.size(); i++) {
                float x = startX + (i * xStep);
                float y = startY - (data.get(i) * yAxisSize / 5);
                mainPath.lineTo(x, y);
            }

            canvas.drawPath(mainPath, mainPaint);

            // 绘制数据点(只在数据点较少时显示)
            if (data.size() < 50) {
                Paint pointPaint = new Paint();
                pointPaint.setColor(waveData.getColor());
                pointPaint.setStyle(Paint.Style.FILL);
                pointPaint.setAntiAlias(true);

                for (int i = 0; i < data.size(); i++) {
                    float x = startX + (i * xStep);
                    float y = startY - (data.get(i) * yAxisSize / 5);
                    canvas.drawCircle(x, y, 4, pointPaint);
                    canvas.drawCircle(x, y, 6, glowPaint);
                }
            }
        }
    }

    private void drawLegend(Canvas canvas) {
        float startX = 60 + xAxisSize;
        float startY = getHeight() - 50 - yAxisSize + 30;

        Paint legendBgPaint = new Paint();
        legendBgPaint.setColor(Color.argb(150, 0, 30, 60));
        legendBgPaint.setStyle(Paint.Style.FILL);
        legendBgPaint.setAntiAlias(true);

        // 绘制图例背景
        float legendWidth = 180;
        float legendHeight = waveDataList.size() * 40 + 20;
        canvas.drawRoundRect(startX - 10, startY - 10,
                startX + legendWidth, startY + legendHeight, 10, 10, legendBgPaint);

        for (int i = 0; i < waveDataList.size(); i++) {
            WaveData waveData = waveDataList.get(i);

            Paint rectPaint = new Paint();
            rectPaint.setColor(waveData.getColor());
            rectPaint.setStyle(Paint.Style.FILL);
            rectPaint.setAntiAlias(true);

            // 绘制图例颜色块
            canvas.drawRect(startX, startY + (i * 40),
                    startX + 20, startY + (i * 40) + 20, rectPaint);

            // 绘制图例文字
            canvas.drawText(waveData.getName(), startX + 100, startY + (i * 40) + 15, textPaint);
        }
    }

    private void drawBorder(Canvas canvas) {
        Paint borderPaint = new Paint();
        borderPaint.setColor(Color.argb(100, 0, 255, 255));
        borderPaint.setStrokeWidth(2);
        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setAntiAlias(true);

        // 绘制外边框
        canvas.drawRect(5, 5, getWidth() - 5, getHeight() - 5, borderPaint);

        // 绘制内发光效果
        Paint innerGlowPaint = new Paint();
        innerGlowPaint.setColor(Color.argb(50, 0, 255, 255));
        innerGlowPaint.setStrokeWidth(1);
        innerGlowPaint.setStyle(Paint.Style.STROKE);
        innerGlowPaint.setAntiAlias(true);

        canvas.drawRect(8, 8, getWidth() - 8, getHeight() - 8, innerGlowPaint);
    }

    // 内部类,用于存储波形数据
    private static class WaveData {
        private String name;
        private int color;
        private List<Float> data;

        public WaveData(String name, int color) {
            this.name = name;
            this.color = color;
            this.data = new ArrayList<>();
        }

        public String getName() {
            return name;
        }

        public int getColor() {
            return color;
        }

        public List<Float> getData() {
            return data;
        }

        public void addData(float value) {
            data.add(value);
        }
    }
}

2.MainActivity.java源码

复制代码
package com.example.wave;

import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.view.WindowManager;
import android.widget.LinearLayout;

import androidx.appcompat.app.AppCompatActivity;

import java.util.Random;

public class MainActivity extends AppCompatActivity {
    private WaveView waveView;
    private Handler handler;
    private Runnable updateRunnable;
    private int time = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

// 全屏模式
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.activity_main);

        // 获取布局容器
        LinearLayout container = findViewById(R.id.container);

        // 创建WaveView实例
        waveView = new WaveView(this);

// 设置科幻风格参数
        waveView.setShowGrid(true);
        waveView.setShowGlowEffect(true);
        waveView.setGridDensity(12);

// 使用科幻风格的颜色
        int[] waveColors = {
                Color.argb(255, 0, 255, 255),   // 青色 - 科幻感
                Color.argb(255, 255, 0, 255),   // 洋红色 - 科幻感
                Color.argb(255, 0, 255, 0)      // 绿色 - 科幻感
        };

        // 设置波形图大小
        waveView.setAxisSize(1600, 500);

        // 添加波形数据系列
        waveView.addWaveData("正弦波", waveColors[0]);
        waveView.addWaveData("余弦波", waveColors[1]);
        waveView.addWaveData("噪声波", waveColors[2]);

        // 将WaveView添加到布局中
        container.addView(waveView);

        // 创建Handler用于定时更新
        handler = new Handler();
        updateRunnable = new Runnable() {
            @Override
            public void run() {
                updateWaveData();
                handler.postDelayed(this, 1000); // 每秒更新一次
            }
        };
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 开始定时更新
        handler.post(updateRunnable);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 停止定时更新
        handler.removeCallbacks(updateRunnable);
    }

    private void updateWaveData() {
        // 生成正弦波数据
        float sinValue = (float) Math.sin(time * 0.1);
        waveView.addDataToWave("正弦波", sinValue * 2 + 2.5f); // 调整幅度和偏移

        // 生成余弦波数据
        float cosValue = (float) Math.cos(time * 0.1);
        waveView.addDataToWave("余弦波", cosValue * 1.5f + 2.5f); // 调整幅度和偏移

        // 生成带噪声的数据
        Random random = new Random();
        float noiseValue = (float) (Math.sin(time * 0.1) + (random.nextFloat() - 0.5f));
        waveView.addDataToWave("噪声波", noiseValue + 2.5f); // 添加偏移

        time++;
    }
}

3.activity_main.xml源码

复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <TextView
        android:id="@+id/titleTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="多波形显示"
        android:textSize="24sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/titleTextView" />

</androidx.constraintlayout.widget.ConstraintLayout>

三、效果图

运行后,程序开始绘制3条曲线图。

相关推荐
一叶飘零_sweeeet3 小时前
从 0 到 1 精通 SkyWalking:分布式系统的 “透视镜“ 技术全解析
java·skywalking
七夜zippoe3 小时前
Java 生态监控体系实战:Prometheus+Grafana+SkyWalking 整合全指南(三)
java·grafana·prometheus
陈遇巧4 小时前
Spring Framework
java·笔记·spring
我是华为OD~HR~栗栗呀4 小时前
20届-高级开发(华为oD)-Java面经
java·c++·后端·python·华为od·华为
摇滚侠5 小时前
java.lang.RuntimeException: java.lang.OutOfMemoryError
java·开发语言·intellij-idea
sibylyue5 小时前
IDEA cannot resolve method
java·ide·intellij-idea
翻斗花园刘大胆6 小时前
JavaWeb之快递管理系统(完结)
java·开发语言·前端·jvm·spring·servlet·java-ee
熙客7 小时前
SpringCloudStream:消息驱动组件
java·分布式·spring cloud·rabbitmq
Arenaschi7 小时前
Android
android·linux·运维·笔记·其他·docker