自定义波形图View,LayoutInflater动态加载控件保存为本地图片
效果图:
页面布局:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="@dimen/dp_145"xmlns:app="http://schemas.android.com/apk/res-auto"android:background="@color/white"><TextViewandroid:id="@+id/tv_index"android:layout_width="@dimen/dp_30"android:layout_height="match_parent"android:layout_gravity="center"android:background="@color/common_btn_clicked"android:gravity="center"android:textColor="@color/white"android:textSize="@dimen/sp_14"tools:text="TH"/><RelativeLayoutandroid:id="@+id/rl_wave_view"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/white"><com.kl.common_base.view.wave.GridViewandroid:layout_width="match_parent"android:layout_height="match_parent"app:bgColor="#f0d3a9"/><com.kl.common_base.view.wave.PdfEcgWaveViewandroid:id="@+id/wave_view"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="visible" /><TextViewandroid:id="@+id/tv_file_create_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="@dimen/dp_20"android:layout_marginTop="@dimen/dp_10"android:text=""android:textColor="@color/colorPrimary"android:textSize="@dimen/sp_12"tools:text="2019年6月26日11:54" /></RelativeLayout>
</LinearLayout>
自定义波形图控件:
package com.kl.common_base.view.wave;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;import com.kl.common_base.R;
import com.kl.common_base.utils.SizeUtils;import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;public class PdfEcgWaveView extends View {private List<Short> pointList = Collections.synchronizedList(new LinkedList<>());private Paint mPaint;private Paint mPaintLine;private int mWidth = 0;private int mHeight = 0;private int mCenterY = 0;public float points[];List<Short> nativeDatas = null;private int len = 0;private int index = 0;private int zoom;private float gapX = 0.2f;private int xSize = 0;private final int maxMillimeter = 25;private final int FILTER_SIZE = 50;private int sampleRate = 8000 / FILTER_SIZE;private int gain = 5;private final int maxMidScopeY = 0;private double screenTotalTime;private int[] lineArray = new int[]{7321, 8521, 9600, 10875};private Map<Integer, Integer> lineMap = new HashMap();
// private List<Float> xList = new ArrayList<>();public PdfEcgWaveView(Context context) {super(context);Log.d("caowj", "55555555555555555555555555");initPaint();}public PdfEcgWaveView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);Log.d("caowj", "66666666666666666666666666");initPaint();}public PdfEcgWaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);Log.d("caowj", "77777777777777777777777777");initPaint();}private void initPaint() {Log.d("caowj", "initPaint--------------");if (mPaint == null) {mPaint = new Paint();mPaint.setColor(Color.BLACK);mPaint.setAntiAlias(true);mPaint.setStrokeWidth(2);mPaint.setStrokeCap(Paint.Cap.ROUND);mPaint.setStyle(Paint.Style.STROKE);}if (mPaintLine == null) {mPaintLine = new Paint();mPaintLine.setColor(getContext().getResources().getColor(R.color.red));mPaintLine.setAntiAlias(true);mPaintLine.setStrokeWidth(2);mPaintLine.setStrokeCap(Paint.Cap.ROUND);mPaintLine.setStyle(Paint.Style.STROKE);}}@Overrideprotected void onSizeChanged(int width, int height, int oldw, int oldh) {mHeight = getHeight();mCenterY = mHeight / 2;mWidth = getWidth();
// Log.d("caowj", "onSizeChanged--------------"+mWidth+",,,"+mHeight+",,,"+mCenterY);zoom = height / maxMillimeter;
// double speed = 0.04;double speed = (double) 2 / ((double) width / zoom);Log.e("caowj", "speed=" + speed);screenTotalTime = width / zoom * speed;gapX = (float) (this.mWidth / (sampleRate * screenTotalTime));xSize = Math.round(this.mWidth / gapX);points = new float[xSize * 4];Log.e("caowj", "初始化计算:zoom=" + zoom + ",screenTotalTime=" + screenTotalTime + ",gapX=" + gapX + ",widthSize=" + xSize);super.onSizeChanged(width, height, oldw, oldh);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {Log.d("caowj", "onMeasure--------------" + widthMeasureSpec + ",,," + heightMeasureSpec + ",,," + mCenterY);super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onDraw(Canvas canvas) {Log.w("caowj", "onDraw-----------" + pointList.size());len = pointList.size();if (len >= 2) {index = xSize - len;
// Log.d("caowj", "drawCube len=" + len + ",widthSize=" + widthSize + ",index=" + index);for (int i = index + 1; i < xSize; i++) {float startX = (i - 1) * gapX;int mIndex = i - index - 1;points[i * 4] = startX;points[i * 4 + 1] = pointList.get(mIndex);points[i * 4 + 2] = i * gapX;points[i * 4 + 3] = pointList.get(i - index);if (lineMap.containsKey(mIndex)) {Log.w("caowj", "找到需要绘制竖线的位置了:" + startX);
// xList.add(startX);int padding = SizeUtils.dp2px(getResources().getDimension(R.dimen.dp_25));canvas.drawLine(startX, padding, startX, mCenterY * 2 - padding, mPaintLine);}}}canvas.drawLines(points, mPaint);super.onDraw(canvas);}public void addWaveDataInVisiable(short[] waveData) {if (nativeDatas == null) {nativeDatas = new ArrayList<>();}for (int i = 0; i < waveData.length; i++) {short y = (short) Math.floor(calcRealMv(maxMidScopeY - waveData[i]) * gain * zoom + mCenterY);nativeDatas.add(y);
// Log.e("caowj", "y=" + y);}Log.e("caowj", "nativeDatas 长度=" + nativeDatas.size());if (nativeDatas.size() >= 800) {addPointThreadExecutor(nativeDatas);nativeDatas = new ArrayList<>();}}private void addPointThreadExecutor(List<Short> nativeDatas) {if (nativeDatas == null) {return;}List<Short> dataList = nativeDatas;synchronized (pointList) {for (int i = 0; i < dataList.size(); i += FILTER_SIZE) {if (pointList.size() >= xSize && xSize > 0) {pointList.remove(0);}pointList.add(dataList.get(i));for (int linePosition : lineArray) {if (linePosition > i - FILTER_SIZE && linePosition <= i) {lineMap.put(pointList.size(), linePosition);}}}}}public void clear() {if (pointList != null) {pointList.clear();}if (nativeDatas != null) {nativeDatas.clear();}points = new float[xSize * 4];postInvalidate();}/*** mintti 计算真实毫伏值** @param point* @return*/private float calcRealMv(int point) {return (float) (point * 3.3 / 32767);
// int magnification = 1000;//TODO 放大倍数
// return (float) (point / magnification * 3.3 / 32767 * 1000);}
}
public static void createWaveImage(Context context, ViewGroup parentView, AudioFile audioFile, String parentDir, String fileName, int index, boolean isLast) {Log.w("caowj", "createWaveImage");View rootView = LayoutInflater.from(context).inflate(R.layout.item_wave_view, null);PdfEcgWaveView waveView = rootView.findViewById(R.id.wave_view);TextView tvTitle = rootView.findViewById(R.id.tv_file_create_date);TextView tvIndex = rootView.findViewById(R.id.tv_index);tvIndex.setText("TL");String[] arr = fileName.split("\\.");String imageName = arr[0] + "(" + index + ")";String imgTitle = "";if (arr[0].startsWith("0_")) {imgTitle = StringUtils.getPositionAiResult(fileName);}if (TextUtils.isEmpty(imgTitle)) {imgTitle = imageName;}tvTitle.setText(imgTitle);int width = SizeUtils.getScreenWidth() * 2 / 3;int height = SizeUtils.dp2px(context.getResources().getDimension(R.dimen.dp_145));layoutView(rootView, width, height);audioFile.refreshPcmDataByPosition(index, 8000 * 2);waveView.addWaveDataInVisiable(audioFile.getData().clone());Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);// 利用bitmap生成画布Canvas canvas = new Canvas(bitmap);// 把view中的内容绘制在画布上rootView.draw(canvas);// 触发draw()new Thread(new Runnable() {@Overridepublic void run() {Log.d("caowj", "生成Bitmap");boolean result = FileUtils.saveWaveBitmap(bitmap, parentDir, imageName + ".jpg");}}).start();}protected static void layoutView(View v, int w, int h) {v.layout(0, 0, w, h);int measuredWidth = View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY);int measuredHeight = View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.EXACTLY);v.measure(measuredWidth, measuredHeight);Log.w("caowj", measuredWidth + "--" + measuredHeight + ";;;" + v.getMeasuredWidth() + "---" + v.getMeasuredHeight());v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());}
相关文章:

自定义波形图View,LayoutInflater动态加载控件保存为本地图片
效果图: 页面布局: <?xml version"1.0" encoding"utf-8"?><LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:la…...
每日一道算法题 求最小公倍数
题目 求最小公倍数_牛客题霸_牛客网 (nowcoder.com) Python 辗转相除法 dividend,divisormap(int,input().split()) #被除数,除数 # remainder0 余数 # 最小公倍数 def lcm(dividend,divisor):# 最大公约数def gcd(dividend,divisor):if 0divisor:return divid…...
【OCC学习18】三维几何对象工具包:TKG3d
【OCC学习18】三维几何对象工具包:TKG3d loveoobaby 已于 2022-08-26 10:10:32 修改 阅读量1.2k 收藏 10 点赞数 1 分类专栏: OpenCascade学习笔记 文章标签: 学习 版权 OpenCascade学习笔记 专栏收录该内容 24 篇文章60 订阅 订阅专栏…...
【Unix】SunOS/Oracle Solaris系统介绍
一.SunOS系统介绍 SunOS 是由 Sun Microsystems 开发的 Unix 操作系统。它最初是为 Sun 的 SPARC 架构计算机设计的,后来也支持了 Intel x86 架构。SunOS 是基于 UNIX System V 4.1 版本,并且随着时间的发展,SunOS 经历了多个版本迭代&#…...

氛围感视频素材高级感的去哪里找啊?带氛围感的素材网站库分享
亲爱的创作者们,大家好!今天我们来聊聊视频创作中至关重要的一点——氛围感。一个好的视频,不仅要有视觉冲击力,还要能够触动观众的情感。那我们应该去哪里寻找这些充满氛围感且高级的视频素材呢?别急,我这…...

基于Java的学生选课系统
第1章 系统概述 1.1概述 背景:随着计算机网络技术的发展,Web 数据库技术已成为应用最为广泛的网站架构基础技术。学生选课系统作为教育单位不可缺少的部分,其内容对于学校的决策者和管理者至关重要。传统的人工管理方式存在效率低、保密性差等…...

802.11漫游流程简单解析与笔记_Part2_05_wpa_supplicant如何通过nl80211控制内核开始关联
最近在进行和802.11漫游有关的工作,需要对wpa_supplicant认证流程和漫游过程有更多的了解,所以通过阅读论文等方式,记录整理漫游相关知识。Part1将记录802.11漫游的基本流程、802.11R的基本流程、与认证和漫游都有关的三层秘钥基础。Part1将包…...

STM32的 DMA(直接存储器访问) 详解
STM32的DMA(Direct Memory Access,直接存储器存取)是一种在单片机中用于高效实现数据传输的技术。它允许外设设备直接访问RAM,不需要CPU的干预,从而释放CPU资源,提高CPU工作效率,本文基于STM32F…...

14-65 剑和诗人39 - 打造你自己的 Devin
绝密 Devin 架构 更具体地说,构建您自己的 AI 代理。 Devin 使用 GPT-4 ,而人们已经开始用 Claude-3-Opus 构建替代方案 Devin 的 UI 体验更好。 例如,它甚至看不到浏览器,但它确实存在于用户面前 此外,你可以随时与它“交谈”,就像与人交谈一样,它会在后…...
JavaScript 把CSDN博客内容存成PDF
F12 - 控制台 -命令行 输入执行:允许粘贴输入执行代码: (function () {use strict;var articleBox $("div.article_content");articleBox.removeAttr("style");var head_str "";var foot_str "";var older…...

uniapp——银行卡号脱敏
样式 代码 {{bankNumber.replace(/(\d{4})(?\d)/g, "●●●● ").replace(/(\d{2})(?\d{2}$)/, " $1")}} 将银行卡号按照每四位一组的方式进行处理,前面的变成 剩下的正常显示...

基于Spring Boot框架的EAM系统设计与实现
摘 要:文章设计并实现一个基于Spring Boot框架的EAM系统,以应对传统人工管理模式存在的低效与信息管理难题。系统利用Java语言、JSP技术、MySQL数据库等技术栈,构建了一个B/S架构的高效管理平台,提升了资产管理的信息化水平。该系…...
不同编程范式中作用域和闭包概念概述
不同编程范式中作用域和闭包概念概述 作用域(Scope)是指变量或函数在程序中的可见性和生命周期范围。它决定了哪些部分的代码可以访问某个变量或函数。在所有编程语言中都用于管理变量和函数的可见性范围,但不同语言可能有不同的作用域级别和…...

ISO/OSI七层模型
ISO:国际标准化/ OSI:开放系统互联 七层协议必背图 1.注意事项: 1.上三层是为用户服务的,下四层负责实际数据传输。 2.下四层的传输单位: 传输层; 数据段(报文) 网络层: 数据包(报…...

Golang | Leetcode Golang题解之第226题翻转二叉树
题目: 题解: func invertTree(root *TreeNode) *TreeNode {if root nil {return nil}left : invertTree(root.Left)right : invertTree(root.Right)root.Left rightroot.Right leftreturn root }...

传感器标定(一)摄像头内参标定
一、使用ROS进行手动标定安装 1、安装 image-view &usb_cam ⽤于驱动相机 sudo apt-get install ros-melodic-image-view sudo apt-get install ros-melodic-usb-cam2、查看系统视频设备 v4l2- ctl -d /dev/video0 --all 查询所有相机具体的参数包括width和height ls /…...

基于门控循环单元 GRU 实现股票单变量时间序列预测(PyTorch版)
前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对…...
Apache tika 实现各种文档内容解析
Apache tika 实现各种文档内容解析 1、依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"…...
Vue3 监听属性
Vue3 监听属性 Vue.js 是一个流行的前端框架,以其响应式系统和组件化开发而闻名。在 Vue3 中,监听属性(Watchers)是一个核心功能,允许开发者监控和响应数据的变化。本文将详细介绍 Vue3 中监听属性的使用方法、场景和最佳实践。 监听属性的基本概念 在 Vue3 中,监听属…...
Transformer模型论文解读、源码分析和项目实践
本文是ChatGPT系列的开篇之作,为什么吧Transformer放到这里呢,因为不管是chatgpt-1, chatgpt-2, chatgpt-3都是以Transformer作为底层基础来实现,相当于chatgpt系列的老祖先了。如果想要深入的了解清楚chatgpt的来龙去…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...

自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...

MLP实战二:MLP 实现图像数字多分类
任务 实战(二):MLP 实现图像多分类 基于 mnist 数据集,建立 mlp 模型,实现 0-9 数字的十分类 task: 1、实现 mnist 数据载入,可视化图形数字; 2、完成数据预处理:图像数据维度转换与…...