参考网址:Android MP3文件录制 + 声音分贝大小自定义View实现_android mediarecorder mp3-优快云博客
先上效果图,该效果图为转载的,以下代码是仿照微信操作修改的
package com.sample.utils;
import android.content.Context;
import android.util.DisplayMetrics;
/**
* 屏幕像素转换工具类
*/
public class DisplayUtil {
public static int px2dp(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
public static int dp2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
public static int getScreenWidth(Context context) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
return dm.widthPixels;
}
public static int getScreenHeight(Context context) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
return dm.heightPixels;
}
public static float getDisplayDensity(Context context) {
if (context == null) {
return -1;
}
return context.getResources().getDisplayMetrics().density;
}
}
package com.sample.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.sample.R;
import com.sample.utils.DisplayUtil;
import java.util.Arrays;
/**
* 描述: 音频条形view,波形居中显示
* Created By liweidong on 2020/7/16
*/
public class AudioLumpView extends View {
private Context context;
//控件宽高
private int width;
private int height;
//条形宽度
private int lumpWidth;
//条形间距
private int lumpSpace;
//条形最小高度
private int lumpMinHeight;
//条形最大高度
private int lumpMaxHeight;
private int middleLeft;
private int middleTop;
//画笔
private Paint paint;
//条形数一半
private int lumpSize;
private int lumpCount;
private byte[] waveData;
private int middleBottom;
private int minus;
private static final float SCALE = 1.5f;
//圆角半径
private int roundRadius;
private TextPaint textPaint;
private boolean isData = false;
float downX,downY,lastX,lastY;
private boolean pointer;// 是否多个手指
private float[] matrixValue= new float[9];// matrix对应的值
private int volume;
public AudioLumpView(Context context) {
super(context);
init(context);
}
public AudioLumpView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AudioLumpView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//设置宽高
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
private void init(Context context){
this.context = context;
int b = DisplayUtil.getScreenWidth(context);
int a = DisplayUtil.px2dp(context,b);
width = DisplayUtil.dp2px(context, a-50);//适配宽度(根据手机屏幕宽度-50)
height = DisplayUtil.dp2px(context, 60);
lumpWidth = DisplayUtil.dp2px(context, 3);
lumpMinHeight = DisplayUtil.dp2px(context, 6);
lumpMaxHeight = DisplayUtil.dp2px(context, 55);
lumpSpace = DisplayUtil.dp2px(context, 5);
roundRadius = DisplayUtil.dp2px(context, 1.5f);
middleLeft = (width - lumpWidth) / 2;
middleTop = (height - lumpMinHeight) / 2;
middleBottom = height / 2 + lumpMinHeight;
lumpSize = middleLeft / (lumpWidth + lumpSpace);
lumpCount = lumpSize * 2 + 1;
paint = new Paint();
paint.setColor(getResources().getColor(R.color.audio_lump));
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(lumpWidth);
textPaint = new TextPaint();
textPaint.setFilterBitmap(true);
}
Canvas canvas1;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
canvas1 = canvas;
canvas1.drawColor(getResources().getColor(R.color.button_default_color));
if (!isData){
drawText(canvas,"按下说话",40,width / 2, height / 2,
getResources().getColor(R.color.myblack));
return;
}
if (waveData == null){//无数据时所有竖线恢复到初始状态
middleTop = (int) (lumpMaxHeight / 2 - (lumpWidth + 2 * SCALE) * 1)+5;
//最中间的条形
canvas.drawRect(middleLeft, middleTop, middleLeft + lumpWidth, height / 1.8f, paint);
//绘制圆角
drawRound(canvas, middleLeft, middleTop - roundRadius,middleLeft + lumpWidth,middleTop + roundRadius , 180 * (-1));
//向左画
for (int i = lumpSize; i > 0; i--){
canvas.drawRect(middleLeft - (lumpSpace + lumpWidth) * (lumpSize + 1 - i), middleTop, middleLeft + lumpWidth - (lumpSpace + lumpWidth) * (lumpSize + 1 - i), height / 1.8f, paint);
//绘制圆角
drawRound(canvas, middleLeft - (lumpSpace + lumpWidth) * (lumpSize + 1 - i), middleTop - roundRadius,middleLeft + lumpWidth - (lumpSpace + lumpWidth) * (lumpSize + 1 - i),middleTop + roundRadius , 180 * (-1));
}
//向右画
for (int i = lumpSize; i < lumpCount; i++){
middleTop = (int) (lumpMaxHeight / 2 + (lumpWidth + 2 * SCALE) * -1)+5;
canvas.drawRect(middleLeft + (lumpSpace + lumpWidth) * (i + 1 - lumpSize), middleTop, middleLeft + lumpWidth + (lumpSpace + lumpWidth) * (i + 1 - lumpSize), height / 1.8f, paint);
//绘制圆角
drawRound(canvas, middleLeft + (lumpSpace + lumpWidth) * (i + 1 - lumpSize), middleTop - roundRadius,middleLeft + lumpWidth + (lumpSpace + lumpWidth) * (i + 1 - lumpSize),middleTop + roundRadius , 180 * -1);
}
return;
}
drawLump(canvas, true);
drawLump(canvas, false);
}
public void setWaveData(int volume,byte[] data) {
this.volume = volume;
if (volume!=0&&data!=null){
this.waveData = readyData(data);
isData = true;
}else
this.waveData = null;
invalidate();
}
public void isData(boolean isData){
this.isData = isData;
invalidate();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void drawLump(Canvas canvas, boolean reverse){
minus = reverse ? 1 : -1;
middleTop = (int) (lumpMaxHeight / 2 - (lumpWidth + waveData[waveData.length - 1] / 4 * SCALE) * minus);
//最中间的条形
canvas.drawRect(middleLeft, middleTop, middleLeft + lumpWidth, height / 2, paint);
//绘制圆角
drawRound(canvas, middleLeft, middleTop - roundRadius,middleLeft + lumpWidth,middleTop + roundRadius , 180 * (-minus));
//向左画
for (int i = lumpSize; i > 0; i--){
middleTop = (int) (lumpMaxHeight / 2 - (lumpWidth + waveData[i] / 4 * SCALE) * minus);
canvas.drawRect(middleLeft - (lumpSpace + lumpWidth) * (lumpSize + 1 - i), middleTop, middleLeft + lumpWidth - (lumpSpace + lumpWidth) * (lumpSize + 1 - i), height / 2, paint);
//绘制圆角
drawRound(canvas, middleLeft - (lumpSpace + lumpWidth) * (lumpSize + 1 - i), middleTop - roundRadius,middleLeft + lumpWidth - (lumpSpace + lumpWidth) * (lumpSize + 1 - i),middleTop + roundRadius , 180 * (-minus));
}
//向右画
for (int i = lumpSize; i < lumpCount; i++){
middleTop = (int) (lumpMaxHeight / 2 + (lumpWidth + waveData[lumpCount - i - 1] / 4 * SCALE) * minus);
canvas.drawRect(middleLeft + (lumpSpace + lumpWidth) * (i + 1 - lumpSize), middleTop, middleLeft + lumpWidth + (lumpSpace + lumpWidth) * (i + 1 - lumpSize), height / 2, paint);
//绘制圆角
drawRound(canvas, middleLeft + (lumpSpace + lumpWidth) * (i + 1 - lumpSize), middleTop - roundRadius,middleLeft + lumpWidth + (lumpSpace + lumpWidth) * (i + 1 - lumpSize),middleTop + roundRadius , 180 * minus);
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void drawRound(Canvas canvas, int left, int top, int right, int bottom, float sweepAngle){
//绘制圆角
canvas.drawArc(left, top, right, bottom, 0, sweepAngle, false, paint);
}
/**
* 预处理数据
*
* @return
*/
private byte[] readyData(byte[] fft) {
byte[] newData = new byte[lumpSize + 2];
for (int i = 0; i < Math.min(fft.length, lumpSize + 2); i++) {
newData[i] = (byte) Math.abs(fft[i]);
}
Arrays.sort(newData);
return newData;
}
private void drawText(Canvas canvas, String str, float size, float startX, float startY, int color){
textPaint.setColor(color);
textPaint.setTypeface(Typeface.DEFAULT_BOLD);//字体
Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);//字体风格
textPaint.setTypeface(font);
textPaint.setTextSize(size);
textPaint.setFakeBoldText(true); // 设置加粗文字
//Paint设置水平居中
textPaint.setTextAlign(Paint.Align.CENTER);
float length = textPaint.measureText(str);
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
// 计算文字高度
float fontHeight = fontMetrics.bottom - fontMetrics.top;
// 计算文字baseline
float textBaseY = height - (height - fontHeight) / 2 - fontMetrics.bottom;
float sX = startX+length/4;
float sY = startY+20;
canvas.drawText(str, sX,sY,textPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//拖动监听
int x = (int) event.getX();
int y = (int) event.getY();
if (event.getPointerCount() > 1) {
pointer = true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://第一个手指初次碰到屏幕触发
downX = x;
downY = y;
System.out.println("ACTION_DOWN...");
pointer = false;
if (listener!=null)
listener.audioStart();
break;
case MotionEvent.ACTION_UP://最后一个手指离开屏幕触发
float upX = (float) Math.abs(x - downX);
float upY = (float) Math.abs(y - downY);
if ((y<=downY||upY > 100) && !pointer) {
System.out.println("ACTION_UP...松手取消");
if (listener!=null)
listener.audioStop();
}
break;
case MotionEvent.ACTION_MOVE://手指在屏幕上滑动
float dx = (float) Math.abs(x - downX);
float dy = (float) Math.abs(y - downY);
if (!pointer) {
System.out.println("ACTION_MOVE...");
boolean bl = false;
if (isData&&listener!=null){
if (dy > 100){
bl = true;
}else if (y<=downY){
bl = false;
}
listener.audioIsStop(bl);
}
}
break;
case MotionEvent.ACTION_POINTER_DOWN://有非主要的手指按下(按下之前已经有手指在屏幕上)
System.out.println("ACTION_POINTER_DOWN...");
break;
case MotionEvent.ACTION_POINTER_UP://有非主要手指抬起(抬起之后还有手指在屏幕上)
System.out.println("ACTION_POINTER_UP...");
break;
}
lastX = x;
lastY = y;
return true;
}
AudioListener listener;
public interface AudioListener{
void audioStart();
void audioStop();
void audioIsStop(boolean bl);
}
public void setListener(AudioListener listener){
this.listener = listener;
}
}