Android 仿微信语音录音小控件

前段时间一直在做IM聊天这方面的撸码工作,涉及到了很多小控件,有时间我会慢慢给大家分享一下我的小成果,希望大家一起学习,一起进步,今天来和大家来说一下Android 仿微信语音录音小控件。

实现效果如下:



(文章结尾给大家献上了Demo下载地址,希望大家喜欢,共同学习,共同进步 ——-Android studio写的)

接下来我们来讲解一下实现思路:
我们要实现这样的效果,其实就是我们点击一个Button,然后出来一个弹窗,要做具体效果展示的都在弹框上面。首先这个点击的Button我们去判断是否有上下滑动的事件,来判断上滑、下滑、触摸点是否在原先位置来显示文字的显示。

我们就要继承Button去实现onTouchEvent,去重写里面的方法来判断上滑、下滑等操作:

 @Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubLog.d("RecordButton", "event.getAction():" + event.getAction());switch (event.getAction()) {case MotionEvent.ACTION_DOWN: // 按下按钮if (recordState != RECORD_ON) {showVoiceDialog(0);downY = event.getY();if (mAudioRecorder != null) {mAudioRecorder.ready();recordState = RECORD_ON;mAudioRecorder.start();callRecordTimeThread();}}break;case MotionEvent.ACTION_MOVE: // 滑动手指float moveY = event.getY();if (downY - moveY > 50) {isCanceled = true;showVoiceDialog(1);}if (downY - moveY < 20) {isCanceled = false;showVoiceDialog(0);}//MAX_RECORD_TIME 最长录音时间剩余时间的提醒if (recodeTime < MAX_RECORD_TIME && recodeTime >= MAX_RECORD_TIME - 10) {if (mRecordDialog.isShowing()) {showVoiceDialog(2);}}//录音时间超过最大时间直接取消if (recodeTime >= MAX_RECORD_TIME) {if (mRecordDialog.isShowing()) {mRecordDialog.dismiss();}}break;case MotionEvent.ACTION_UP: // 松开手指if (recordState == RECORD_ON) {recordState = RECORD_OFF;if (mRecordDialog.isShowing()) {mRecordDialog.dismiss();}mAudioRecorder.stop();mRecordThread.interrupt();voiceValue = 0.0;if (isCanceled) {mAudioRecorder.deleteOldFile();} else {if (recodeTime < MIN_RECORD_TIME) {showWarnToast("时间太短  录音失败");mAudioRecorder.deleteOldFile();} else {if (listener != null) {listener.recordEnd(mAudioRecorder.getFilePath(), recodeTime);}}}isCanceled = false;this.setText("按住说话");}break;}return true;}

判断录音的时间,提示相对应得提示,如:录音时间太短、录音倒计时10秒的显示、超出录音时间,录音自动取消、录音最长时间60秒等(注:最短最长时间都可以自己设置)

录音的时间显示

 private static final int MIN_RECORD_TIME = 1; // 最短录音时间,单位秒private static final int MAX_RECORD_TIME = 60;//最长录音时间,单位秒录音时间短:if (recodeTime < MIN_RECORD_TIME) {showWarnToast("时间太短  录音失败");mAudioRecorder.deleteOldFile();} else {if (listener != null) {listener.recordEnd(mAudioRecorder.getFilePath(), recodeTime);}}录音倒计时:
//设置倒计时private void setDialogTime() {//MAX_RECORD_TIME 最长录音时间剩余时间的提醒if (recodeTime < MAX_RECORD_TIME && recodeTime >= MAX_RECORD_TIME - 10) {if (mRecordDialog.isShowing()) {showVoiceDialog(2);}}//录音时间超过最大时间直接取消if (recodeTime >= MAX_RECORD_TIME) {if (mRecordDialog.isShowing()) {mRecordDialog.dismiss();}}}case MotionEvent.ACTION_MOVE: // 滑动手指float moveY = event.getY();if (downY - moveY > 50) {isCanceled = true;showVoiceDialog(1);}if (downY - moveY < 20) {isCanceled = false;showVoiceDialog(0);}//MAX_RECORD_TIME 最长录音时间剩余时间的提醒if (recodeTime < MAX_RECORD_TIME && recodeTime >= MAX_RECORD_TIME - 10) {if (mRecordDialog.isShowing()) {showVoiceDialog(2);}}//录音时间超过最大时间直接取消if (recodeTime >= MAX_RECORD_TIME) {if (mRecordDialog.isShowing()) {mRecordDialog.dismiss();}}break;录音倒计时的提示需要在两个地方都要进行设置,第一个写的地方是通知时间到了倒计时显示时间时时时刻刻发的通知提醒,第二个地方,是在case MotionEvent.ACTION_MOVE:
(滑动手指),因为我们手指放在录音的按键上,其实时时刻刻,我们手指存在的细微的滑动的,在这里我们也要去通知设置倒计时,防止Diolog显示showVoiceDialog(1)/ showVoiceDialog(0)和 showVoiceDialog(2)来回交换,产生显示冲突

完整的自定义的RecordButton(录音小控件)代码

package Voice;import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import com.example.administrator.voice.R;/**** madreain 录音控件*/
public class RecordButton extends Button {private static final int MIN_RECORD_TIME = 1; // 最短录音时间,单位秒private static final int MAX_RECORD_TIME = 60;//最长录音时间,单位秒private static final int RECORD_OFF = 0; // 不在录音private static final int RECORD_ON = 1; // 正在录音private Dialog mRecordDialog;private RecordStrategy mAudioRecorder;private Thread mRecordThread;private RecordListener listener;private int recordState = 0; // 录音状态private float recodeTime = 0.0f; // 录音时长,如果录音时间太短则录音失败private double voiceValue = 0.0; // 录音的音量值private boolean isCanceled = false; // 是否取消录音private float downY;private TextView dialogTextView;private ImageView dialogImg;private ImageView dialogImgSize;private TextView dialogTextTime;private Context mContext;public RecordButton(Context context) {super(context);// TODO Auto-generated constructor stubinit(context);}public RecordButton(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stubinit(context);}public RecordButton(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stubinit(context);}private void init(Context context) {mContext = context;this.setText("按住说话");}public void setAudioRecord(RecordStrategy record) {this.mAudioRecorder = record;}public void setRecordListener(RecordListener listener) {this.listener = listener;}// 录音时显示Dialogprivate void showVoiceDialog(int flag) {if (mRecordDialog == null) {mRecordDialog = new Dialog(mContext, R.style.Dialogstyle);mRecordDialog.setContentView(R.layout.dialog_record);dialogImg = (ImageView) mRecordDialog.findViewById(R.id.record_dialog_img);dialogTextView = (TextView) mRecordDialog.findViewById(R.id.record_dialog_txt);dialogImgSize = (ImageView) mRecordDialog.findViewById(R.id.record_dialog_img_size);dialogTextTime = (TextView) mRecordDialog.findViewById(R.id.record_dialog_time);}switch (flag) {case 1:dialogImg.setVisibility(VISIBLE);dialogTextTime.setVisibility(GONE);
//          dialogImg.setImageResource(R.drawable.record_cancel);// TODO: 2016/8/13
//          dialogTextView.setText("松开手指可取消录音");
//          this.setText("松开手指 取消录音");dialogTextView.setText("松指取消发送");this.setText("松开结束");break;//最长录音时间剩余时间的提醒case 2://10秒倒计时的显示dialogImg.setVisibility(GONE);dialogTextTime.setVisibility(VISIBLE);dialogTextTime.setText(((int) (MAX_RECORD_TIME - recodeTime) + 1) + "");break;default:dialogImg.setVisibility(VISIBLE);dialogTextTime.setVisibility(GONE);
//          dialogImg.setImageResource(R.drawable.record_animate_01);dialogImg.setImageResource(R.mipmap.im_microphone);dialogImgSize.setImageResource(R.mipmap.chat_volume_00);
//          dialogTextView.setText("向上滑动可取消录音");
//          this.setText("松开手指 完成录音");dialogTextView.setText("上滑取消发送");this.setText("松开结束");break;}dialogTextView.setTextSize(14);if (mRecordDialog != null) {mRecordDialog.show();}}// 录音时间太短时Toast显示private void showWarnToast(String toastText) {Toast toast = new Toast(mContext);View warnView = LayoutInflater.from(mContext).inflate(R.layout.toast_warn, null);toast.setView(warnView);toast.setGravity(Gravity.CENTER, 0, 0);// 起点位置为中间
//        toast.setDuration(500);//设置显示时间toast.show();}// 开启录音计时线程private void callRecordTimeThread() {mRecordThread = new Thread(recordThread);mRecordThread.start();}// 录音Dialog图片随录音音量大小切换private void setDialogImage() {if (voiceValue < 1000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_01);} else if (voiceValue > 1000.0 && voiceValue < 3000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_02);} else if (voiceValue > 3000.0 && voiceValue < 5000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_03);} else if (voiceValue > 5000.0 && voiceValue < 7000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_04);} else if (voiceValue > 7000.0 && voiceValue < 9000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_05);} else if (voiceValue > 11000.0 && voiceValue < 13000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_06);} else if (voiceValue > 13000.0 && voiceValue < 15000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_07);} else if (voiceValue > 15000.0 && voiceValue < 17000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_08);} else if (voiceValue > 17000.0 && voiceValue < 19000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_09);} else if (voiceValue > 19000.0 && voiceValue < 20000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_10);} else if (voiceValue > 20000.0 && voiceValue < 22000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_11);} else if (voiceValue > 22000.0) {dialogImgSize.setImageResource(R.mipmap.chat_volume_12);}//      if (voiceValue < 600.0) {//          dialogImg.setImageResource(R.drawable.record_animate_01);
//      } else if (voiceValue > 600.0 && voiceValue < 1000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_02);
//      } else if (voiceValue > 1000.0 && voiceValue < 1200.0) {//          dialogImg.setImageResource(R.drawable.record_animate_03);
//      } else if (voiceValue > 1200.0 && voiceValue < 1400.0) {//          dialogImg.setImageResource(R.drawable.record_animate_04);
//      } else if (voiceValue > 1400.0 && voiceValue < 1600.0) {//          dialogImg.setImageResource(R.drawable.record_animate_05);
//      } else if (voiceValue > 1600.0 && voiceValue < 1800.0) {//          dialogImg.setImageResource(R.drawable.record_animate_06);
//      } else if (voiceValue > 1800.0 && voiceValue < 2000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_07);
//      } else if (voiceValue > 2000.0 && voiceValue < 3000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_08);
//      } else if (voiceValue > 3000.0 && voiceValue < 4000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_09);
//      } else if (voiceValue > 4000.0 && voiceValue < 6000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_10);
//      } else if (voiceValue > 6000.0 && voiceValue < 8000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_11);
//      } else if (voiceValue > 8000.0 && voiceValue < 10000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_12);
//      } else if (voiceValue > 10000.0 && voiceValue < 12000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_13);
//      } else if (voiceValue > 12000.0) {//          dialogImg.setImageResource(R.drawable.record_animate_14);
//      }
//}// 录音线程private Runnable recordThread = new Runnable() {@Overridepublic void run() {recodeTime = 0.0f;while (recordState == RECORD_ON) {{try {Thread.sleep(100);recodeTime += 0.1;// 获取音量,更新dialogif (!isCanceled) {voiceValue = mAudioRecorder.getAmplitude();recordHandler.sendEmptyMessage(1);}} catch (InterruptedException e) {e.printStackTrace();}}}}};@SuppressLint("HandlerLeak")private Handler recordHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {setDialogImage();setDialogTime();}};//设置倒计时private void setDialogTime() {//MAX_RECORD_TIME 最长录音时间剩余时间的提醒if (recodeTime < MAX_RECORD_TIME && recodeTime >= MAX_RECORD_TIME - 10) {if (mRecordDialog.isShowing()) {showVoiceDialog(2);}}//录音时间超过最大时间直接取消if (recodeTime >= MAX_RECORD_TIME) {if (mRecordDialog.isShowing()) {mRecordDialog.dismiss();}}}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubLog.d("RecordButton", "event.getAction():" + event.getAction());switch (event.getAction()) {case MotionEvent.ACTION_DOWN: // 按下按钮if (recordState != RECORD_ON) {showVoiceDialog(0);downY = event.getY();if (mAudioRecorder != null) {mAudioRecorder.ready();recordState = RECORD_ON;mAudioRecorder.start();callRecordTimeThread();}}break;case MotionEvent.ACTION_MOVE: // 滑动手指float moveY = event.getY();if (downY - moveY > 50) {isCanceled = true;showVoiceDialog(1);}if (downY - moveY < 20) {isCanceled = false;showVoiceDialog(0);}//MAX_RECORD_TIME 最长录音时间剩余时间的提醒if (recodeTime < MAX_RECORD_TIME && recodeTime >= MAX_RECORD_TIME - 10) {if (mRecordDialog.isShowing()) {showVoiceDialog(2);}}//录音时间超过最大时间直接取消if (recodeTime >= MAX_RECORD_TIME) {if (mRecordDialog.isShowing()) {mRecordDialog.dismiss();}}break;case MotionEvent.ACTION_UP: // 松开手指if (recordState == RECORD_ON) {recordState = RECORD_OFF;if (mRecordDialog.isShowing()) {mRecordDialog.dismiss();}mAudioRecorder.stop();mRecordThread.interrupt();voiceValue = 0.0;if (isCanceled) {mAudioRecorder.deleteOldFile();} else {if (recodeTime < MIN_RECORD_TIME) {showWarnToast("时间太短  录音失败");mAudioRecorder.deleteOldFile();} else {if (listener != null) {listener.recordEnd(mAudioRecorder.getFilePath(), recodeTime);}}}isCanceled = false;this.setText("按住说话");}break;}return true;}public interface RecordListener {public void recordEnd(String filePath, float time);}
}

Android 仿微信语音录音小控件Demo

Android 仿微信语音录音小控件相关推荐

  1. php支付密码控件,Android高仿微信支付密码输入控件实例代码

    这篇文章主要为大家详细介绍了Android高仿微信支付密码输入控件的具体实现代码,供大家参考,具体内容如下 像微信支付密码控件,在app中是一个多么司空见惯的功能.最近,项目需要这个功能,于是乎就实现 ...

  2. android放微信@功能,Android仿微信语音消息的录制和播放功能

    一.简述 效果: 实现功能: 长按Button时改变Button显示文字,弹出Dialog(动态更新音量),动态生成录音文件,开始录音: 监听手指动作,规定区域.录音状态下手指划出规定区域取消录音,删 ...

  3. android 录音的格式转换,Android仿微信录音功能(录音后的raw文件转mp3文件)

    现在很多时候需要用到录音,然后如果我们的App是ios和android两端的话,就要考虑录音的文件在两端都能使用,这个时候就需要适配,两端的录音文件都要是mp3文件,这样才能保证两边都能播放. 针对这 ...

  4. java 头像 微信群_仿微信群头像九宫格控件 LQRNineGridImageView

    软件介绍 仿微信群头像九宫格控件 一.简介: 参照Android 仿微信群聊头像文章学习开发的一个仿微信群头像九宫格控件,感谢博主Loften_93663469. 效果如下: 二.使用: 1.在自己项 ...

  5. android 仿微信语音聊天

    android 仿微信语音聊天 跟着imooc老师学习 代码地址: https://github.com/tingsky9985/Weixin_Recorder

  6. Android仿微信语音聊天界面设计

    这篇文章主要为大家详细介绍了Android仿微信语音聊天界面设计代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 有段时间没有看视频了,昨天晚上抽了点空时间,又看了下鸿洋大神的视频教程,又抽时间 ...

  7. android仿微信语音聊天功能,Android仿微信发送语音消息的功能及示例代码

    微信的发送语音是有一个向上取消的,我们使用ontouchlistener来监听手势,然后做出相应的操作就行了. 直接上代码: //语音操作对象 private mediaplayer mplayer ...

  8. Android 仿微信语音聊天音量大小显示控件

    某日用微信语音功能聊天,发现当我使用语音功能时,会弹出一个窗口,窗口中间有一个控件会实时的显示我说话声音的大小(即分贝).当时觉得挺好玩,决定也仿制一个,效果如下 分析控件显示效果,可判断左边是一个i ...

  9. Android利用MedioRecorder使用仿微信语音录音以及播放(总结)

    今天模仿着微信的发送语音功能做了一下,现将步骤以及其中遇到的问题记录一下,以便以后查看. 实现功能:1.录制语音并显示到列表中:2.点击列表中的语音自动进行播放:3.录制语音时以及播放语音时的动画效果 ...

最新文章

  1. java实现最长连续子序列_最长公共子序列 ||
  2. vscode 插件设置
  3. Cs Tip13: 删除安装文件
  4. 总分 Score Inflation
  5. java学习笔记2022.1.12
  6. 你是第几名:Excel 中 Large 和 Small 的用法
  7. Linux下编译FFMpeg
  8. java 分词搜索_基于JAVA的小型中文分词系统
  9. python结构_科学网—Python与结构分析(1)---反应谱 - 潘超的博文
  10. 联想小新pro16按不了Fn+Q键
  11. 证书服务器,及申请证书。
  12. 2019年计算机类毕业设计论文题目推荐
  13. 仙境传说 RO手游 自动技能 定时加状态脚本
  14. 南京地图njmaps使用,以公众版为例
  15. 基于python实现的双月模型
  16. 通信原理:课程学习笔记3之确知信号和随机过程
  17. php把字符串变为数组_php把字符串转为数组的方法
  18. 【观察】 2016年度中国企业级市场十大新闻
  19. 从根本上理解 机器学习中真实值、观测值、预测值的区别
  20. 函数式编程另类指南 (转载)

热门文章

  1. 10 个快速提升技术水平的方法
  2. 企业中B端常用的十大产品分类详情
  3. 关于网络性能的一些指标
  4. win7 无法打开vscode 1.71版本
  5. 新手提问!求解答QAQADODB.Recordset 错误 #x27;800a0bb9#x27; 参数类型不正确,或不在可以接受的范围之内,或与其他参数冲突。
  6. MATLAB-xcorr函数
  7. 乐器php毕业论文,打击乐器在音乐课堂教学中的应用
  8. P4313 文理分科
  9. mysql:本地mysql不能被其他主机连接解决方法
  10. 【HDR学习】HDR视频相关知识讲解(一)