一个功能强大的Android音频波形视图组件,仿喜马拉雅录音剪切界面,支持音频波形显示、编辑、剪切、缩放等功能。
- 音频波形显示 - 支持实时显示音频波形数据
- 编辑模式 - 支持选择音频片段进行编辑操作
- 音频剪切 - 支持剪切选中的音频片段
- 整段替换 - 支持替换选中音频片段
- 波形缩放 - 支持手势缩放波形显示
- 覆盖录制 - 支持覆盖录制功能
- 滚动支持 - 支持手势滚动浏览长音频
- 播放动画 - 支持播放进度动画显示
- 文字背景 - 支持为时间文字添加背景样式
- 高度自定义 - 丰富的属性配置,满足各种UI需求
<com.shetj.waveview.AudioWaveView
android:id="@+id/audioWaveView"android:layout_width="match_parent"android:layout_height="300dp"app:wv_rect_level="10"app:wv_one_second_rect_size="25"app:wv_bottom_line_margin="20dp"app:wv_can_scroll="true"app:wv_center_line_width="2dp"app:wv_cut_icon="@mipmap/icon_test_touch"app:wv_cut_icon_size="25dp"app:wv_cut_line_width="1dp"app:wv_cut_time_text_size="12sp"app:wv_time_progress_text_color="@color/black"app:wv_time_progress_text_size="12sp"app:wv_show_text_background="true"app:wv_text_background_color="#80000000"app:wv_text_background_horizontal_padding="8dp"app:wv_text_background_vertical_padding="4dp"app:wv_text_background_corner_radius="4dp" />val audioWaveView = findViewById<AudioWaveView>(R.id.audioWaveView)
// 设置监听器
audioWaveView.setListener(object:AudioWaveView.OnChangeListener {
overridefunonUpdateCurrentPosition(position:Long, duration:Long) {
// 当前播放位置更新
}
overridefunonUpdateCutPosition(startPosition:Long, endPosition:Long) {
// 剪切位置更新
}
overridesuspendfunonCutAudio(startTime:Long, endTime:Long): Boolean {
// 执行音频剪切操作returntrue
}
})
// 添加音频数据
audioWaveView.addFrame(0.5f, 1000L) // 添加单个帧数据AudioWaveView 提供了丰富的XML属性配置,按功能分为以下几个部分:
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
wv_top_line_margin | dimension | 30dp | 顶部线距离顶部的高度 |
wv_bottom_line_margin | dimension | 30dp | 底部线距离底部的高度 |
wv_top_bottom_line_color | color | #c8cad0 | 顶部和底部线的颜色 |
wv_top_bottom_line_width | dimension | 3dp | 顶部和底部线的宽度 |
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
wv_rect_scale | float | 1.0f | 缩放级别,范围0.1~1.4 |
wv_rect_level | integer | 10 | 矩形分级数量,决定波形高度层次 |
wv_one_second_rect_size | float | 25 | 一秒钟包含的矩形数量 |
wv_rect_width | dimension | 2dp | 矩形的宽度 |
wv_rect_corner_radius | dimension | 2dp | 矩形的圆角半径 |
wv_rect_space | dimension | 2dp | 矩形之间的间距 |
wv_rect_right_color | color | #c8cad0 | 中线右边矩形的颜色 |
wv_rect_left_color | color | #93b3ea | 中线左边矩形的颜色 |
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
wv_center_line_color | color | #93b3ea | 中线颜色 |
wv_center_line_width | dimension | 2dp | 中线宽度 |
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
wv_cut_icon | reference | - | 剪切标记图标资源 |
wv_cut_icon_size | dimension | 30dp | 剪切图标大小 |
wv_cut_line_color | color | RED | 剪切线颜色 |
wv_cut_line_width | dimension | 3dp | 剪切线宽度 |
wv_cut_time_text_color | color | RED | 剪切时间文字颜色 |
wv_cut_time_text_size | dimension | 18sp | 剪切时间文字大小 |
wv_cut_select_color | color | #33FFBB22 | 选中区域背景颜色 |
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
wv_time_progress_text_color | color | #c8cad0 | 时间刻度文字颜色 |
wv_time_progress_text_size | dimension | 18sp | 时间刻度文字大小 |
wv_can_scroll | boolean | true | 是否可以滚动 |
wv_show_center_line | boolean | true | 是否显示中线 |
wv_show_top_bottom_line | boolean | true | 是否显示上下线 |
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
wv_show_text_background | boolean | false | 是否显示文本背景 |
wv_text_background_color | color | #80000000 | 文本背景颜色 |
wv_text_background_horizontal_padding | dimension | 8dp | 文本背景水平内边距 |
wv_text_background_vertical_padding | dimension | 4dp | 文本背景垂直内边距 |
wv_text_background_corner_radius | dimension | 4dp | 文本背景圆角半径 |
除了XML属性配置外,AudioWaveView还提供了丰富的代码配置方法:
// 设置中线颜色
audioWaveView.setCenterLineColor(Color.BLUE)
// 设置左侧波形颜色
audioWaveView.setLeftPaintColor(Color.GREEN)
// 设置右侧波形颜色
audioWaveView.setRightPaintColor(Color.GRAY)
// 设置剪切标记颜色
audioWaveView.setCutMarkerPointPaintColor(Color.RED)
// 设置选中区域背景颜色
audioWaveView.setCutSelectPaintColor(Color.parseColor("#33FFBB22"))// 设置波形宽度
audioWaveView.setWaveWidth(3f)
// 设置波形间距
audioWaveView.setWaveSpace(1f)
// 设置波形圆角
audioWaveView.setWaveCornerRadius(4f)
// 设置缩放比例
audioWaveView.setWaveScale(1.2f)
// 设置时间文字大小
audioWaveView.setTimeSize(14f)// 设置是否显示文字背景
audioWaveView.setShowTextBackground(true)
// 设置文字背景颜色
audioWaveView.setTextBackgroundColor(Color.parseColor("#80000000"))
// 设置文字背景内边距
audioWaveView.setTextBackgroundPadding(10f, 6f) // 水平10dp,垂直6dp// 设置文字背景圆角
audioWaveView.setTextBackgroundCornerRadius(6f)// 添加单个音频帧funaddFrame(frame:Float, duration:Long)
// 批量添加音频帧funaddFrames(index:Int, newFrameArray:FrameArray, frameDuration:Long, editModel:Boolean = true)
// 替换音频片段funreplaceFrames(startTime:Long, endTime:Long, newFrameArray:FrameArray, newFrameDuration:Long, editModel:Boolean = true)
// 清空所有数据funclearFrame()
// 获取所有音频帧数据fungetFrames(): ArrayList<Float>
// 获取音频总时长fungetDuration(): Long// 设置当前播放位置funsetCurrentPosition(currentTime:Long)
// 获取当前播放位置fungetCurrentPosition(): Long// 开始播放动画funstartPlayAnim(speed:Float = 1.0f)
// 暂停播放动画funpausePlayAnim()
// 检查是否正在播放funisPlaying(): Boolean// 开启编辑模式funstartEditModel()
// 开启编辑模式(指定时间范围)funstartEditModel(startTime:Long? = null, endTime:Long? = null)
// 关闭编辑模式funcloseEditModel()
// 检查是否处于编辑模式funisEditModel(): Boolean// 剪切选中片段suspendfuncutSelect(): Boolean// 开始覆盖录制suspendfunstartOverwrite(): Boolean// 获取剪切开始时间fungetCutStartTime(): Long// 获取剪切结束时间fungetCutEndTime(): Long// 设置是否可以滚动funsetEnableScroll(enable:Boolean, toEnd:Boolean = false)
// 滚动到末尾funscrollToEnd(needAnim:Boolean = true)
// 滚动到开头funscrollToStart(needAnim:Boolean = true)
// 检查是否已滚动到末尾funisScrollEnd(): BooleaninterfaceOnChangeListener {
/** * 当前播放位置更新 * @param position 当前位置(毫秒) * @param duration 总时长(毫秒)*/funonUpdateCurrentPosition(position:Long, duration:Long)
/** * 剪切位置更新 * @param startPosition 开始位置(毫秒) * @param endPosition 结束位置(毫秒)*/funonUpdateCutPosition(startPosition:Long, endPosition:Long)
/** * 执行音频剪切 * @param startTime 开始时间(毫秒) * @param endTime 结束时间(毫秒) * @return 是否剪切成功*/suspendfunonCutAudio(startTime:Long, endTime:Long): Boolean/** * 剪切完成回调*/funonCutFinish()
/** * 缩放级别更新 * @param scale 当前缩放比例*/funonUpdateScale(scale:Float)
/** * 编辑模式状态变化 * @param isEditModel 是否处于编辑模式*/funonEditModelChange(isEditModel:Boolean)
}编辑模式允许用户选择音频片段进行剪切、替换等操作:
// 开启编辑模式
audioWaveView.startEditModel()
// 开启编辑模式并指定选择范围
audioWaveView.startEditModel(startTime =1000L, endTime =5000L)
// 监听编辑模式状态变化
audioWaveView.setListener(object:AudioWaveView.OnChangeListener {
overridefunonEditModelChange(isEditModel:Boolean) {
if (isEditModel) {
// 进入编辑模式
showEditControls()
} else {
// 退出编辑模式
hideEditControls()
}
}
overridefunonUpdateCutPosition(startPosition:Long, endPosition:Long) {
// 更新选择范围显示
updateSelectionInfo(startPosition, endPosition)
}
})覆盖录制功能允许从当前位置开始覆盖后续的音频内容:
// 开始覆盖录制
lifecycleScope.launch {
val success = audioWaveView.startOverwrite()
if (success) {
// 覆盖录制开始成功
startRecording()
}
}新增的文字背景功能可以为时间显示文字添加背景,提高可读性:
<com.shetj.waveview.AudioWaveView
...
app:wv_show_text_background="true"app:wv_text_background_color="#80000000"app:wv_text_background_horizontal_padding="8dp"app:wv_text_background_vertical_padding="4dp"app:wv_text_background_corner_radius="4dp" />// 启用文字背景
audioWaveView.setShowTextBackground(true)
// 设置背景颜色(半透明黑色)
audioWaveView.setTextBackgroundColor(Color.parseColor("#80000000"))
// 设置内边距
audioWaveView.setTextBackgroundPadding(8f, 4f)
// 设置圆角
audioWaveView.setTextBackgroundCornerRadius(4f)本质是通过偏移量的变化来实现滚动效果:
- 使用
Scroller+DecelerateInterpolator实现手势阻尼效果 - 通过
mOffsetX变量控制整体内容的偏移
- 使用
ScaleGestureDetector检测缩放手势 - 通过
mScaleFactor变量控制缩放比例 - 重新计算并绘制UI元素
- 剪切中线以后的数据(触发剪切回调)
- 在末端开始添加新的音频数据
- 实现无缝的覆盖录制体验
- 剪切选中部分的数据
- 在指定位置插入新的音频数据
- 文件操作需要使用者自行实现
使用 PorterDuffXfermode 的 SRC_ATOP 模式:
- 给左边一半画一个大矩形
- 只绘制重叠部分,实现精确的颜色分割效果
- 计算文字的实际尺寸
- 根据内边距计算背景矩形范围
- 使用
drawRoundRect绘制圆角背景
项目包含完整的示例应用,展示了所有功能的使用方法:
- demo-record - 完整的录音、剪切、播放示例
- ✅ 真实录音功能
- ✅ 音频剪切功能
- ✅ 音频播放功能
- ✅ 覆盖录制功能
- 克隆项目到本地
- 使用 Android Studio 打开项目
- 运行
demo-record模块 - 体验完整的音频编辑功能
A: AudioWaveView 只处理UI交互逻辑,不直接支持PCM数据。你需要:
- 将音频文件转换为PCM格式
- 从PCM数据中提取分贝值
- 根据
wv_rect_level和wv_one_second_rect_size设置合适的数据 - 使用
addFrame()或addFrames()添加数据
A: 关键参数说明:
wv_rect_level="10"- 波形分为10个高度级别wv_one_second_rect_size="25"- 一秒显示25个矩形- 示例:一个矩形表示40ms(1000ms ÷ 25 = 40ms)
A: 检查以下设置:
- 确保
wv_can_scroll="true" - 确保没有在播放状态(播放时会禁用手势)
- 检查是否正确设置了监听器
A: 使用 wv_cut_icon 属性:
app:wv_cut_icon="@mipmap/your_custom_icon"
app:wv_cut_icon_size="30dp"A: 确保正确配置:
app:wv_show_text_background="true"
app:wv_text_background_color="#80000000"- ✅ 新增文字背景功能 - 支持为时间文字添加背景样式
- ✅ 优化渲染性能 - 减少不必要的遍历,直接计算索引范围
- ✅ 完善API文档 - 提供更详细的使用说明和示例
- ✅ 音频波形显示
- ✅ 编辑模式支持
- ✅ 音频剪切功能
- ✅ 整段替换功能
- ✅ 波形缩放功能
- ✅ 覆盖录制功能
- ✅ 滚动浏览支持
- ✅ 播放动画效果
- ✅ 文字背景样式
- ✅ 性能优化
本项目采用 MIT 许可证,详情请查看 LICENSE 文件。
欢迎提交 Issue 和 Pull Request 来帮助改进这个项目!
如果你有任何问题或建议,请通过以下方式联系:
- GitHub Issues: 提交问题
⭐ 如果这个项目对你有帮助,请给个Star支持一下!