博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
仿same音频采样UI效果
阅读量:6553 次
发布时间:2019-06-24

本文共 5110 字,大约阅读时间需要 17 分钟。

先看一下效果图(这个效果图是以前的,后面更新了代码,画面更加流程,完全没有卡顿):

一开始我看了这个效果图,是一脸的懵逼,完全没有思路。按照sdk提供的控件肯定是做不出来这种效果图,只能自己画,通过继承View,绘制UI。

先说一下整体思路

  • 首先这个效果图,需要拆分成两部分,一部分是上面表示录音时间的刻度尺,还有一部分是下面的录音的采样波形图
  • 整个画面的移动,这部分也是最难的一部分。我通过录音时间,和采样频率,计算出刻度尺上滑动的距离,然后通过scrollTo方法移动整个画布,来达到效果的
  • 绘制的过程中,只能绘制当前屏幕的内容,绘制整个刻度尺范围内的采样图的肯定会卡顿

整体的思路基本是这样子。下面讲解一下具体的实现过程。

  • 先定义一个BaseAudioRecord继承自View,该类主要控制滑动,初始化自定义参数等
  • 创建一个AudioRecord 类继承BaseAudioRecord, 该类主要负责画面绘制工作

AudioRecord绘制

1.先讲解一下AudioRecord绘制的第一步,绘制上面体现录音时间的刻度尺的绘制。重写onDraw方法,通过canvas来绘制。

代码如下:

private void drawScale(Canvas canvas) {        int firstPoint = (getScrollX() - mDrawOffset) / scaleIntervalLength;        int lastPoint = (getScrollX() + canvas.getWidth() + mDrawOffset) / (scaleIntervalLength);        for (int i = firstPoint; i < lastPoint; i++) {            float locationX = i * scaleIntervalLength;            if (i % intervalCount == 0) {                canvas.drawLine(locationX, ruleHorizontalLineHeight - bigScaleStrokeLength, locationX, ruleHorizontalLineHeight, bigScalePaint);                if (showRuleText) {                    int index = i / intervalCount;                    canvas.drawText(formatTime(index), locationX + bigScaleStrokeWidth + 5, ruleHorizontalLineHeight - bigScaleStrokeLength + ruleTextSize / 1.5f, ruleTextPaint);                }            } else {                canvas.drawLine(locationX, ruleHorizontalLineHeight - smallScaleStrokeLength, locationX, ruleHorizontalLineHeight, smallScalePaint);            }        }        //画轮廓线        canvas.drawLine(getScrollX(), ruleHorizontalLineHeight, getScrollX() + canvas.getWidth(), ruleHorizontalLineHeight, ruleHorizontalLinePaint);    }复制代码

上面代码说明如下:

  • getScrollX() 表示画布移动的距离,往右侧移动是正数,往左侧移动是负数,值表示画布在屏幕内移动的平素点的个数
  • firstPoint 表示绘制的第一个点,减去一个 mDrawOffset 表示往左侧屏幕多绘制了一个缓冲区域
  • lastPoint 表示绘制的最后一个点,加上一个 mDrawOffset表示往右侧屏幕多绘制了一个缓冲区域
  • scaleIntervalLength 表示刻度间隔
  • intervalCount 表示两个大刻度之间小刻度的间隔数

2.绘制中间的采样波形图

代码如下:

private void drawLine(Canvas canvas) {        int middleLineY = canvas.getHeight() / 2;        canvas.drawLine(getScrollX(), middleLineY, getScrollX() + canvas.getWidth(), middleLineY, middleHorizontalLinePaint);        //从数据源中找出需要绘制的矩形        List
drawRectList = getDrawSampleLineList(canvas); if (drawRectList == null || drawRectList.size() == 0) { return; } //绘制采样点 for (SampleLineModel sampleLineModel : drawRectList) { canvas.drawLine(sampleLineModel.startX, sampleLineModel.startY, sampleLineModel.stopX, sampleLineModel.stopY, linePaint); int invertedStartY = canvas.getHeight() / 2; float invertedStopY = invertedStartY + sampleLineModel.stopY - sampleLineModel.startY; canvas.drawLine(sampleLineModel.startX, invertedStartY, sampleLineModel.stopX, invertedStopY, lineInvertedPaint); } }复制代码
  • 矩形的绘制,是用drawLine来表示的,矩形宽用线宽表示即可。从中心的水平横线上下各绘制了同等长度的线,用来表示采样的波形图
  • 同样采样波形的绘制,也只绘制屏幕内的采样波形

AudioRecord两块区域绘制的核心代码基本就是这样子了

BaseAudioRecord 控制移动

1.重写onTouchEvent()方法,根据手势移动,来移动画布

核心代码如下:

@Override    public boolean onTouchEvent(MotionEvent event) {        float currentX = event.getX();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                mLastX = currentX;                break;            case MotionEvent.ACTION_MOVE:                float moveX = mLastX - currentX;                mLastX = currentX;                scrollBy((int) (moveX), 0);                break;            }                     return true;    }复制代码
  • return true; 将onTouchEvent触摸事件消费掉,一遍能够执行到ACTION_MOVE
  • 通过scrollBy来移动画布,距离通过,手指滑动的距离获取float moveX = mLastX - currentX;

2.通过ObjectAnimator.ofFloat()方法来移动画布,开启动画

核心代码如下: 动画开始:

float startX = getScrollX();            //小于半屏的时候,要重新计算偏移量,因为有个左滑的动作            float endX = maxLength - getMeasuredWidth() / 2;            float dx = Math.abs(endX - startX);            final double duration = 1000 * dx / (recordSamplingFrequency * (lineWidth + rectGap));            animator = ObjectAnimator.ofFloat(this, "translateX", startX, endX);            animator.setInterpolator(new LinearInterpolator());            animator.setDuration((long) Math.floor(duration));            animator.removeAllListeners();            animator.start();复制代码

移动画布:

public void setTranslateX(float translateX) {        this.translateX = translateX;        scrollTo((int) translateX, 0);        if (isStartRecordTranslateCanvas) {            translateVerticalLineX = getScrollX() + getMeasuredWidth() / 2 + rectGap;        }        onTick(getScrollX() + getMeasuredWidth() / 2);    }复制代码

根据画布移动的距离,算出时间,再根据定义好的采样频率,回调采样函数,生成波形图:

private void onTick(float translateX) {   if (isRecording) {        long duration = (long) (translateX * recordTimeInMillis / maxLength);        if (duration > getSampleCount() * recordDelayMillis) {            makeSampleLine(recordCallBack.getSamplePercent());        }          } }复制代码

这个自定义的录音采集声音波形的UI基本上就完成了,有兴趣的小伙伴可以去查看源码,有什么不对的地方,欢迎指正交流。

源码中,有一个播放器的类AudioRecordMp3.java,采用了AudioRecord录制的音频,使用了Lame将AudioRecord录制的pcm格式的音频实时转码成MP3格式,支持暂停录制,删除上一段录音的功能。

源码里面还有一个播放声音的波形图,原理和上面类似,效果如下:

转载于:https://juejin.im/post/5a3720c851882506e50cbb19

你可能感兴趣的文章
C# DataSet数据导入Excel 修正版- .net FrameWork 4.0以上
查看>>
NSBundle
查看>>
Linux kernel memory-faq.txt
查看>>
java 企业 网站源码 后台 springmvc SSM 前台 静态化 代码生成器
查看>>
[Delphi] FMXUI - ListView用法简介
查看>>
再不做题就老了,这个假期就这么地了
查看>>
oracle中的三种异常情况
查看>>
6.18 学习记录
查看>>
centos6.7下网络设置
查看>>
[Android四大组件之二]——Service
查看>>
趋中法则
查看>>
一首《人道》,献给正在辛苦加班的程序员朋友们
查看>>
记录关于使用ADO.NET 连接池连接Oracle时Session信息不更新的坑
查看>>
nodejs windows下安装运行
查看>>
基于JavaMail的Java邮件发送:简单邮件发送
查看>>
maven引用net.sf.json-lib
查看>>
Spring IOC容器的初始化流程
查看>>
51Nod 1199 Money out of Thin Air(dfs序加线段树)
查看>>
Scrum立会报告+燃尽图(十一月二十三日总第三十一次):界面修改及新页面添加...
查看>>
实验二 20145237 20155226 2015234 实验报告 固件程序设计
查看>>