自定义波形图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的来龙去…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
