自定义波形图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的来龙去…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...

2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...