Android自定义View实现微信语音界面

作者:Black_Hao 时间:2022-03-27 20:35:27 

前言

因为最近的项目需要使用录音功能,开始的想法是Button+OnTouchListener+Dialog实现,在大部分手机中都没问题,只有MI8会偶尔无法触发MotionEvent.ACTION_UP,导致程序异常。所以就自己写了个自定义View来实现,主要也是通过监听
OnTouchListener+Dialog来实现。这里只实现了自定义View,并不涉及录音和播放。效果图如下:

Android自定义View实现微信语音界面

代码

代码并不复杂,配合注释应该很容易理解。


/**
* Author : BlackHao
* Time : 2019/4/18 14:03
* Description : 自定义录音按钮布局界面
*/
public class PressedView extends View implements View.OnTouchListener {

private int normalRes;
 private String normalText = "";
 private int pressedRes;
 private String pressedText = "";
 //
 private Paint paint;
 private Rect rect;
 //当前是否是按下状态
 private boolean isPressed = false;
 //
 private PressCallback callback;
 //按下的位置y坐标
 private int pressedY = 0;
 //当前是否是outSize
 private boolean isOutSize = false;
 //字体dp大小
 private static int TEXT_SIZE = 20;
 //对话框相关
 private Dialog soundVolumeDialog = null;
 //音量图片
 private ImageView soundVolumeImg = null;
 //对话框背景
 private RelativeLayout soundVolumeLayout = null;

public PressedView(Context context) {
   super(context);
   init();
 }

public PressedView(Context context, @Nullable AttributeSet attrs) {
   super(context, attrs);
   init();
 }

public PressedView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
   super(context, attrs, defStyleAttr);
   init();
 }

private void init() {
   //
   paint = new Paint();
   paint.setAntiAlias(true);
   paint.setTextSize(DensityUtil.dip2px(getContext(), TEXT_SIZE));
   paint.setColor(Color.WHITE);
   rect = new Rect();
   //
   normalRes = R.drawable.blue_btn_bk;
   normalText = "按住 说话";
   pressedRes = R.drawable.red_btn_bk;
   pressedText = "松开 结束";
   //
   setOnTouchListener(this);
   //
   initSoundVolumeDlg();
 }

@Override
 protected void onDraw(Canvas canvas) {
   super.onDraw(canvas);
   rect.set(0, 0, getWidth(), getHeight());
   if (!isPressed) {
     setBackgroundResource(normalRes);
     drawTextOnRect(canvas, rect, normalText);
   } else {
     setBackgroundResource(pressedRes);
     drawTextOnRect(canvas, rect, pressedText);
   }
 }

@Override
 public boolean onTouch(View v, MotionEvent event) {
   switch (event.getAction()) {
     case MotionEvent.ACTION_DOWN:
       pressedY = (int) event.getRawY();
       isOutSize = false;
       if (!isPressed) {
         isPressed = true;
         postInvalidate();
         if (callback != null) {
           //回调
           callback.onStartRecord();
           //按下,弹出对话框
           soundVolumeImg.setImageResource(R.mipmap.sound_volume_01);
           soundVolumeImg.setVisibility(View.VISIBLE);
           soundVolumeLayout.setBackgroundResource(R.mipmap.sound_volume_default_bk);
           soundVolumeDialog.show();
         }
       }
       break;
     case MotionEvent.ACTION_UP:
       if (isPressed) {
         isPressed = false;
         postInvalidate();
         if (callback != null) {
           int upY = (int) event.getRawY();
           if (pressedY - upY < getHeight()) {
             //录音结束
             if (soundVolumeDialog.isShowing()) {
               soundVolumeDialog.dismiss();
             }
             callback.onStopRecord();
           } else {
             //录音取消
             if (soundVolumeDialog.isShowing()) {
               soundVolumeDialog.dismiss();
             }
             callback.onCancelRecord();
           }
         }
       }
       break;
     case MotionEvent.ACTION_MOVE:
       if (isPressed && callback != null) {
         int upY = (int) event.getRawY();
         if (pressedY - upY < getHeight()) {
           if (isOutSize) {
             isOutSize = false;
             soundVolumeLayout.setBackgroundResource(R.mipmap.sound_volume_default_bk);
           }
         } else {
           if (!isOutSize) {
             isOutSize = true;
             soundVolumeLayout.setBackgroundResource(R.mipmap.sound_volume_cancel_bk);
           }
         }
       }
       break;
   }
   return true;
 }

public void setCallback(PressCallback callback) {
   this.callback = callback;
 }

public interface PressCallback {

//开始录音
   void onStartRecord();

//停止录音
   void onStopRecord();

//取消录音
   void onCancelRecord();
 }

/**
  * 在指定矩形中间drawText
  *
  * @param canvas   画布
  * @param targetRect 指定矩形
  * @param text    需要绘制的Text
  */
 private void drawTextOnRect(Canvas canvas, Rect targetRect, String text) {
   Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
   // 获取baseLine
   int baseline = targetRect.top + (targetRect.bottom - targetRect.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
   // 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()
   paint.setTextAlign(Paint.Align.CENTER);
   canvas.drawText(text, targetRect.centerX(), baseline, paint);
 }

/**
  * 初始化音量信息对话框
  */
 private void initSoundVolumeDlg() {
   soundVolumeDialog = new Dialog(getContext(), R.style.SoundVolumeStyle);
   soundVolumeDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
   soundVolumeDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
       WindowManager.LayoutParams.FLAG_FULLSCREEN);
   soundVolumeDialog.setContentView(R.layout.tt_sound_volume_dialog);
   soundVolumeDialog.setCanceledOnTouchOutside(true);
   soundVolumeImg = (ImageView) soundVolumeDialog.findViewById(R.id.sound_volume_img);
   soundVolumeLayout = (RelativeLayout) soundVolumeDialog.findViewById(R.id.sound_volume_bk);
 }

/**
  * 根据分贝值设置录音时的音量动画
  */
 public void setVolume(int voiceValue) {
   if (voiceValue < 200.0) {
     soundVolumeImg.setImageResource(R.mipmap.sound_volume_01);
   } else if (voiceValue > 200.0 && voiceValue < 600) {
     soundVolumeImg.setImageResource(R.mipmap.sound_volume_02);
   } else if (voiceValue > 600.0 && voiceValue < 1200) {
     soundVolumeImg.setImageResource(R.mipmap.sound_volume_03);
   } else if (voiceValue > 1200.0 && voiceValue < 2400) {
     soundVolumeImg.setImageResource(R.mipmap.sound_volume_04);
   } else if (voiceValue > 2400.0 && voiceValue < 10000) {
     soundVolumeImg.setImageResource(R.mipmap.sound_volume_05);
   } else if (voiceValue > 10000.0 && voiceValue < 28000.0) {
     soundVolumeImg.setImageResource(R.mipmap.sound_volume_06);
   } else if (voiceValue > 28000.0) {
     soundVolumeImg.setImageResource(R.mipmap.sound_volume_07);
   }
 }

}

结语

源码github地址:仿微信语音界面

来源:https://blog.csdn.net/a512337862/article/details/90602156

标签:Android,微信,语音
0
投稿

猜你喜欢

  • 浅谈Java中复制数组的方式

    2022-04-14 23:30:27
  • Unity3d实现无限循环滚动背景

    2022-11-02 05:04:22
  • Android四种数据存储的应用方式

    2023-07-25 05:01:06
  • IDEA的Swing可视化插件JFormDesigner详解

    2023-09-23 08:02:54
  • SpringBoot定时任务动态扩展ScheduledTaskRegistrar详解

    2023-04-23 08:44:06
  • java多线程读取多个文件的方法

    2022-12-05 04:37:45
  • Java 7大常见排序方法实例详解

    2022-01-09 05:16:46
  • Android开发之子线程操作UI的几种方法

    2022-08-05 23:17:52
  • Java synchronized重量级锁实现过程浅析

    2023-10-25 14:10:17
  • java 中设计模式(值对象)的实例详解

    2021-12-27 14:15:08
  • C#的String和StringBuilder详解

    2022-06-21 09:51:31
  • Android自定义GestureDetector实现手势ImageView

    2023-12-18 05:16:35
  • executor包执行器功能

    2023-07-26 21:07:36
  • DevExpress设置饼状图的Lable位置实例

    2022-02-02 15:53:37
  • 解析C#设计模式编程中外观模式Facade Pattern的应用

    2021-08-08 05:10:37
  • 解决Java中的java.io.IOException: Broken pipe问题

    2022-01-24 00:40:34
  • Java获取任意http网页源代码的方法

    2022-07-06 01:45:37
  • Spring Boot整合Mybatis并完成CRUD操作的实现示例

    2023-11-09 04:36:46
  • java.lang.ExceptionInInitializerError异常的解决方法

    2023-01-13 04:23:16
  • 浅谈Java锁的膨胀过程以及一致性哈希对锁膨胀的影响

    2023-06-03 15:03:38
  • asp之家 软件编程 m.aspxhome.com