在一些音乐类应用中, 经常会展示随着节奏上下起伏的波纹信息, 这些波纹形象地传达了声音信息, 可以提升用户体验, 那么是如何实现的呢? 可以使用Visualizer类获取当前播放的声音信息, 并绘制在画布上, 使用波纹展示即可. 我来讲解一下使用方法.

主要

(1) Visualizer类提取波纹信息的方式.

(2) 应用动态权限管理的方法.

(3) 分离自定义视图的展示和逻辑.

1. 基础准备

Android 6.0引入动态权限管理, 在这个项目中, 会使用系统的音频信息, 因此把权限管理引入这个项目, 参考. Gradle配置引入了Lambda表达式, 参考.

页面布局, 使用自定义的波纹视图控件.

android:id="@+id/main_wv_waveform"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

效果

2. 首页逻辑

添加动态权限管理, 在启动页面时, 获取应用所需的音频权限.

RendererFactory工厂类创建波纹的绘制类SimpleWaveformRender.

startVisualiser方法获取当前播放音乐的音频信息.

注意页面关闭, 在onPause时, 释放Visualiser类.

public class MainActivity extends AppCompatActivity {

private static final int CAPTURE_SIZE = 256; // 获取这些数据, 用于显示

private static final int REQUEST_CODE = 0;

// 权限

private static final String[] PERMISSIONS = new String[]{

Manifest.permission.RECORD_AUDIO,

Manifest.permission.MODIFY_AUDIO_SETTINGS

};

@Bind(R.id.main_wv_waveform) WaveformView mWvWaveform; // 波纹视图

private Visualizer mVisualizer; // 音频可视化类

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

ButterKnife.bind(this);

RendererFactory rendererFactory = new RendererFactory();

mWvWaveform.setRenderer(rendererFactory.createSimpleWaveformRender(ContextCompat.getColor(this, R.color.colorPrimary), Color.WHITE));

}

@Override protected void onResume() {

super.onResume();

PermissionsChecker checker = new PermissionsChecker(this);

if (checker.lakesPermissions(PERMISSIONS)) {

PermissionsActivity.startActivityForResult(this, REQUEST_CODE, PERMISSIONS);

} else {

startVisualiser();

}

}

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == REQUEST_CODE && resultCode == PermissionsActivity.PERMISSIONS_DENIED) {

finish();

}

}

// 设置音频线

private void startVisualiser() {

mVisualizer = new Visualizer(0); // 初始化

mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {

@Override

public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {

if (mWvWaveform != null) {

mWvWaveform.setWaveform(waveform);

}

}

@Override

public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {

}

}, Visualizer.getMaxCaptureRate(), true, false);

mVisualizer.setCaptureSize(CAPTURE_SIZE);

mVisualizer.setEnabled(true);

}

// 释放

@Override protected void onPause() {

if (mVisualizer != null) {

mVisualizer.setEnabled(false);

mVisualizer.release();

}

super.onPause();

}

}

Visualizer类

new Visualizer(0), 初始化; setCaptureSize, 获取波纹数量; setEnabled, 启动监听;

setDataCaptureListener, 第一个参数是回调, 使用WaveFormData或FftData; 第二个是更新率; 第三个是判断使用WaveFormData; 第四个是判断使用FftData, 第三\四个均与回调的返回值有关.

3. 波纹视图

页面框架, 分离显示和逻辑, 使用接口渲染, 输入画布Canvas和波纹Waveform.

/**

* 音频波纹视图

*

* Created by wangchenlong on 16/2/11.

*/

public class WaveformView extends View {

private WaveformRenderer mRenderer; // 绘制类

private byte[] mWaveform; // 波纹形状

public WaveformView(Context context) {

super(context);

}

public WaveformView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public WaveformView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@TargetApi(21)

public WaveformView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

}

public void setRenderer(WaveformRenderer renderer) {

mRenderer = renderer;

}

public void setWaveform(byte[] waveform) {

mWaveform = Arrays.copyOf(waveform, waveform.length); // 数组复制

invalidate(); // 设置波纹之后, 需要重绘

}

@Override protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (mRenderer != null) {

mRenderer.render(canvas, mWaveform);

}

}

}

数组复制Arrays.copyOf(), 在设置波纹后重绘页面invalidate().

4. 波纹逻辑

核心部分renderWaveform, 渲染波纹.

把页面分为网格样式, 根据波纹值, 绘制曲线; 没有波纹, 绘制居中水平直线.

/**

* 波纹渲染逻辑

*

* Created by wangchenlong on 16/2/12.

*/

public class SimpleWaveformRenderer implements WaveformRenderer {

private static final int Y_FACTOR = 0xFF; // 2的8次方 = 256

private static final float HALF_FACTOR = 0.5f;

@ColorInt private final int mBackgroundColor;

private final Paint mForegroundPaint;

private final Path mWaveformPath;

private SimpleWaveformRenderer(@ColorInt int backgroundColor, Paint foregroundPaint, Path waveformPath) {

mBackgroundColor = backgroundColor;

mForegroundPaint = foregroundPaint;

mWaveformPath = waveformPath;

}

public static SimpleWaveformRenderer newInstance(@ColorInt int backgroundColor, @ColorInt int foregroundColour) {

Paint paint = new Paint();

paint.setColor(foregroundColour);

paint.setAntiAlias(true); // 抗锯齿

paint.setStrokeWidth(8.0f); // 设置宽度

paint.setStyle(Paint.Style.STROKE); // 填充

Path waveformPath = new Path();

return new SimpleWaveformRenderer(backgroundColor, paint, waveformPath);

}

@Override public void render(Canvas canvas, byte[] waveform) {

canvas.drawColor(mBackgroundColor);

float width = canvas.getWidth();

float height = canvas.getHeight();

mWaveformPath.reset();

// 没有数据

if (waveform != null) {

// 绘制波形

renderWaveform(waveform, width, height);

} else {

// 绘制直线

renderBlank(width, height);

}

canvas.drawPath(mWaveformPath, mForegroundPaint);

}

private void renderWaveform(byte[] waveform, float width, float height) {

float xIncrement = width / (float) (waveform.length); // 水平块数

float yIncrement = height / Y_FACTOR; // 竖直块数

int halfHeight = (int) (height * HALF_FACTOR); // 居中位置

mWaveformPath.moveTo(0, halfHeight);

for (int i = 1; i < waveform.length; ++i) {

float yPosition = waveform[i] > 0 ?

height - (yIncrement * waveform[i]) : -(yIncrement * waveform[i]);

mWaveformPath.lineTo(xIncrement * i, yPosition);

}

mWaveformPath.lineTo(width, halfHeight); // 最后的点, 水平居中

}

// 居中画一条直线

private void renderBlank(float width, float height) {

int y = (int) (height * HALF_FACTOR);

mWaveformPath.moveTo(0, y);

mWaveformPath.lineTo(width, y);

}

}

绘制移动moveTo, 绘制直线lineTo.

动画效果

通过绘制波纹, 可以类似地绘制一些连续数据, 更加直观地展示, 提升用户体验.

android录音波浪动画_Android使用音频信息绘制动态波纹相关推荐

  1. android录音波浪动画_Android 自定义波浪动画--让进度浪起来~

    waveview <Android 自定义波浪动画之"让进度浪起来~"> 转载请注明来自 傻小孩b_移动开发(http://www.jianshu.com/users/ ...

  2. android录音波浪动画_Android 自定义 view 实现波浪动画进度条

    最近在做项目时需要实现这样一种动画,类似于波浪形的进度动画,粗略的看了一下,发现好像类似于正余弦曲线实现的,但是Android 没有相关的API,所以需要我们动手画出来,所以现在在此记录一下学习过程, ...

  3. android录音波浪动画_Android自定义View实现波浪动画

    本文实例为大家分享了Android自定义View实现波浪动画的具体代码,供大家参考,具体内容如下 效果演示 代码调用与实现效果 xml中调用 android:layout_width="ma ...

  4. 使用音频信息绘制动态波纹

    欢迎Follow我的GitHub, 关注我的CSDN. 本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导.在京东即可购买:https://item.jd.com/123 ...

  5. android录音波浪动画_Android实现波浪效果 - WaveView

    效果图 先上效果图 screenshot.gif 实现 WaveView的属性 WaveView的属性 Wate Level(水位) - 波浪静止时水面距离底部的高度 Amplitude(振幅) - ...

  6. android录音波浪动画_Android实现炫酷的波浪下载Loading动画

    1. 简介和效果分析 一直都觉得有很多loading动画挺炫酷的,然后自己看过一些之后也想实现一个,加强一下对绘制view的练习,能力有限,很多地方的实现的有欠考虑和逻辑优化,不管怎么样画了两天还是把 ...

  7. android录音波浪动画_Android语音输入的波浪效果 – WaveView

    效果展示 源码地址 实现思路 绘制正弦波形 水平移动波形,即可得到破浪效果. 正弦波形的绘制 private void createShader() { ... Bitmap bitmap = Bit ...

  8. android咖啡动画,WaveLineView 一款性能内存友好的录音波浪动画

    WaveLineView 一款内存友好的录音漂亮的波浪动画 效果图(实际效果更好) Usage Step1 allprojects { repositories { ... maven { url ' ...

  9. android采用MVP漫画APP、适配刘海屏、小黄车主界面、录音波浪动画、综合APP等源码

    Android精选源码 一款采用MVP架构的仿完整漫画APP源码 Android适配刘海屏幕 基于Xmpp协议的即时通讯社交软件(客户端+服务端) Android小黄车(ofo)app主页菜单效果 一 ...

最新文章

  1. Insightface项目爬坑指南+使用本地数据集训练流程(MXNET版)
  2. exfat分配单元大小选多少_NTFS/exFAT/FAT32,这三个常见选项是什么意思?
  3. 数据结构——快速排序(使用Java)
  4. POJ2155 Matrix二维线段树经典题
  5. LeetCode 101. Symmetric Tree
  6. java+构造函数+native_java中native的用法
  7. 工业相机与镜头选型方法(含实例)
  8. ubuntu18之wine
  9. java三角形边长_java三角形怎么求边?
  10. 『可道云』内网穿透牛刀小试,会敲键盘就能搭建的私有云网盘
  11. VUE进阶篇Part9(render函数)
  12. Oracle 数据库表空间的管理
  13. Linux 命令整理(一)
  14. 2019最新撩妹聊天技巧恋爱神器
  15. R语言 无敌小抄 cheatsheet
  16. CRC原理简析——史上最清新脱俗简单易懂的CRC解析
  17. linux下centos生成火车动画sl命令
  18. 计算机类期刊审稿周期
  19. 【Genome Biology 2023】EvoAug:通过进化启发的数据增强,提高基因组 DNN 的泛化和可解释性
  20. 苹果助手开发随笔系列:4、获取应用列表以及访问应用内共享目录

热门文章

  1. excel隐藏的选项卡和命令栏怎么找回?
  2. 2019年天猫商家如何通过积分运营来达到用户运营的效果?
  3. Http请求:Google调用本地摄像头权限开启
  4. React 高阶组件(HOC)
  5. JVM学习笔记② JVM运行时数据区域
  6. ERROR: cannot download default sources list from: https://raw.githubusercontent.com/ros/rosdistro/ma
  7. python实现微信朋友圈点赞_使用vue做类似于微信点赞的效果?
  8. ue4 小知识点 als advanced locomotion system v4 foot ik 坑
  9. 财报对比:GREE和DeNA由来已久的竞争
  10. 如何写会议 Rebuttal