有段时间没有看视频了,昨天晚上抽了点空时间,又看了下鸿洋大神的视频教程,又抽时间写了个学习记录。代码和老师讲的基本一样,网上也有很多相同的博客。我只是在AndroidStudio环境下写的。

—-主界面代码——

public class MainActivity extends Activity {

private ListView mListView;

private ArrayAdapter mAdapter;

private List mDatas = new ArrayList();

private AudioRecorderButton mAudioRecorderButton;

private View animView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mListView = (ListView) findViewById(R.id.id_listview);

mAudioRecorderButton = (AudioRecorderButton) findViewById(R.id.id_recorder_button);

mAudioRecorderButton.setFinishRecorderCallBack(new AudioRecorderButton.AudioFinishRecorderCallBack() {

public void onFinish(float seconds, String filePath) {

Recorder recorder = new Recorder(seconds, filePath);

mDatas.add(recorder);

//更新数据

mAdapter.notifyDataSetChanged();

//设置位置

mListView.setSelection(mDatas.size() - 1);

}

});

mAdapter = new RecoderAdapter(this, mDatas);

mListView.setAdapter(mAdapter);

//listView的item点击事件

mListView.setOnItemClickListener(new OnItemClickListener() {

public void onItemClick(AdapterView> arg0, View view, int position, long id) {

// 声音播放动画

if (animView != null) {

animView.setBackgroundResource(R.drawable.adj);

animView = null;

}

animView = view.findViewById(R.id.id_recoder_anim);

animView.setBackgroundResource(R.drawable.play_anim);

AnimationDrawable animation = (AnimationDrawable) animView.getBackground();

animation.start();

// 播放录音

MediaPlayerManager.playSound(mDatas.get(position).filePath, new MediaPlayer.OnCompletionListener() {

public void onCompletion(MediaPlayer mp) {

//播放完成后修改图片

animView.setBackgroundResource(R.drawable.adj);

}

});

}

});

}

@Override

protected void onPause() {

super.onPause();

MediaPlayerManager.pause();

}

@Override

protected void onResume() {

super.onResume();

MediaPlayerManager.resume();

}

@Override

protected void onDestroy() {

super.onDestroy();

MediaPlayerManager.release();

}

—自定义Button——-

/**

* @param

* @author ldm

* @description 自定义Button

* @time 2016/6/25 9:26

*/

public class AudioRecorderButton extends Button {

// 按钮正常状态(默认状态)

private static final int STATE_NORMAL = 1;

//正在录音状态

private static final int STATE_RECORDING = 2;

//录音取消状态

private static final int STATE_CANCEL = 3;

//记录当前状态

private int mCurrentState = STATE_NORMAL;

//是否开始录音标志

private boolean isRecording = false;

//判断在Button上滑动距离,以判断 是否取消

private static final int DISTANCE_Y_CANCEL = 50;

//对话框管理工具类

private DialogManager mDialogManager;

//录音管理工具类

private AudioManager mAudioManager;

//记录录音时间

private float mTime;

// 是否触发longClick

private boolean mReady;

//录音准备

private static final int MSG_AUDIO_PREPARED = 0x110;

//音量发生改变

private static final int MSG_VOICE_CHANGED = 0x111;

//取消提示对话框

private static final int MSG_DIALOG_DIMISS = 0x112;

/**

* @description 获取音量大小的线程

* @author ldm

* @time 2016/6/25 9:30

* @param

*/

private Runnable mGetVoiceLevelRunnable = new Runnable() {

public void run() {

while (isRecording) {//判断正在录音

try {

Thread.sleep(100);

mTime += 0.1f;//录音时间计算

mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);//每0.1秒发送消息

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

};

private Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case MSG_AUDIO_PREPARED:

//显示对话框

mDialogManager.showRecordingDialog();

isRecording = true;

// 开启一个线程计算录音时间

new Thread(mGetVoiceLevelRunnable).start();

break;

case MSG_VOICE_CHANGED:

//更新声音

mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));

break;

case MSG_DIALOG_DIMISS:

//取消对话框

mDialogManager.dimissDialog();

break;

}

super.handleMessage(msg);

}

};

public AudioRecorderButton(Context context, AttributeSet attrs) {

super(context, attrs);

mDialogManager = new DialogManager(context);

//录音文件存放地址

String dir = Environment.getExternalStorageDirectory() + "/ldm_voice";

mAudioManager = AudioManager.getInstance(dir);

mAudioManager.setOnAudioStateListener(new AudioManager.AudioStateListener() {

public void wellPrepared() {

mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);

}

});

// 由于这个类是button所以在构造方法中添加监听事件

setOnLongClickListener(new OnLongClickListener() {

public boolean onLongClick(View v) {

mReady = true;

mAudioManager.prepareAudio();

return false;

}

});

}

public AudioRecorderButton(Context context) {

this(context, null);

}

/**

* @description 录音完成后的回调

* @author ldm

* @time 2016/6/25 11:18

* @param

*/

public interface AudioFinishRecorderCallBack {

void onFinish(float seconds, String filePath);

}

private AudioFinishRecorderCallBack finishRecorderCallBack;

public void setFinishRecorderCallBack(AudioFinishRecorderCallBack listener) {

finishRecorderCallBack = listener;

}

/**

* @param

* @description 处理Button的OnTouchEvent事件

* @author ldm

* @time 2016/6/25 9:35

*/

@Override

public boolean onTouchEvent(MotionEvent event) {

//获取TouchEvent状态

int action = event.getAction();

// 获得x轴坐标

int x = (int) event.getX();

// 获得y轴坐标

int y = (int) event.getY();

switch (action) {

case MotionEvent.ACTION_DOWN://手指按下

changeState(STATE_RECORDING);

break;

case MotionEvent.ACTION_MOVE://手指移动

if (isRecording) {

//根据x,y的坐标判断是否需要取消

if (wantToCancle(x, y)) {

changeState(STATE_CANCEL);

} else {

changeState(STATE_RECORDING);

}

}

break;

case MotionEvent.ACTION_UP://手指放开

if (!mReady) {

reset();

return super.onTouchEvent(event);

}

if (!isRecording || mTime < 0.6f) {//如果时间少于0.6s,则提示录音过短

mDialogManager.tooShort();

mAudioManager.cancel();

// 延迟显示对话框

mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1000);

} else if (mCurrentState == STATE_RECORDING) {

//如果状态为正在录音,则结束录制

mDialogManager.dimissDialog();

mAudioManager.release();

if (finishRecorderCallBack != null) {

finishRecorderCallBack.onFinish(mTime, mAudioManager.getCurrentFilePath());

}

} else if (mCurrentState == STATE_CANCEL) { // 想要取消

mDialogManager.dimissDialog();

mAudioManager.cancel();

}

reset();

break;

}

return super.onTouchEvent(event);

}

/**

* 恢复状态及标志位

*/

private void reset() {

isRecording = false;

mTime = 0;

mReady = false;

changeState(STATE_NORMAL);

}

private boolean wantToCancle(int x, int y) {

// 超过按钮的宽度

if (x < 0 || x > getWidth()) {

return true;

}

// 超过按钮的高度

if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {

return true;

}

return false;

}

/**

* @param

* @description 根据状态改变Button显示

* @author ldm

* @time 2016/6/25 9:36

*/

private void changeState(int state) {

if (mCurrentState != state) {

mCurrentState = state;

switch (state) {

case STATE_NORMAL:

setBackgroundResource(R.drawable.btn_recorder_normal);

setText(R.string.str_recorder_normal);

break;

case STATE_RECORDING:

setBackgroundResource(R.drawable.btn_recorder_recording);

setText(R.string.str_recorder_recording);

if (isRecording) {

mDialogManager.recording();

}

break;

case STATE_CANCEL:

setBackgroundResource(R.drawable.btn_recorder_recording);

mDialogManager.wantToCancel();

setText(R.string.str_recorder_want_cancel);

break;

}

}

}

}

—-对话框管理工具类——

/**

* @description 对话框管理工具类

* @author ldm

* @time 2016/6/25 11:53

* @param

*/

public class DialogManager {

//弹出对话框

private Dialog mDialog;

//录音图标

private ImageView mIcon;

//音量显示 图标

private ImageView mVoice;

//对话框上提示文字

private TextView mLable;

//上下文对象

private Context mContext;

public DialogManager(Context context) {

this.mContext = context;

}

/**

* @param

* @description 显示对话框

* @author ldm

* @time 2016/6/25 9:56

*/

public void showRecordingDialog() {

//根据指定sytle实例化Dialog

mDialog = new Dialog(mContext, R.style.AudioDialog);

LayoutInflater inflater = LayoutInflater.from(mContext);

View view = inflater.inflate(R.layout.dialog_recorder, null);

mDialog.setContentView(view);

mIcon = (ImageView) view.findViewById(R.id.id_recorder_dialog_icon);

mVoice = (ImageView) view.findViewById(R.id.id_recorder_dialog_voice);

mLable = (TextView) view.findViewById(R.id.id_recorder_dialog_label);

mDialog.show();

}

/**

* @param

* @description 正在录音状态的对话框

* @author ldm

* @time 2016/6/25 10:08

*/

public void recording() {

if (mDialog != null && mDialog.isShowing()) {

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLable.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.recorder);

mLable.setText("手指上滑,取消发送");

}

}

/**

* @param

* @description 取消录音状态对话框

* @author ldm

* @time 2016/6/25 10:08

*/

public void wantToCancel() {

if (mDialog != null && mDialog.isShowing()) {

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.GONE);

mLable.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.cancel);

mLable.setText("松开手指,取消发送");

}

}

/**

* @param

* @description时间过短提示的对话框

* @author ldm

* @time 2016/6/25 10:09

*/

public void tooShort() {

if (mDialog != null && mDialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.GONE);

mLable.setVisibility(View.VISIBLE);

mIcon.setImageResource(R.drawable.voice_to_short);

mLable.setText("录音时间过短");

}

}

/**

* @param

* @description

* @author ldm

* @time 2016/6/25 取消(关闭)对话框

*/

public void dimissDialog() {

if (mDialog != null && mDialog.isShowing()) { //显示状态

mDialog.dismiss();

mDialog = null;

}

}

// 显示更新音量级别的对话框

public void updateVoiceLevel(int level) {

if (mDialog != null && mDialog.isShowing()) { //显示状态

mIcon.setVisibility(View.VISIBLE);

mVoice.setVisibility(View.VISIBLE);

mLable.setVisibility(View.VISIBLE);

//设置图片的id,我们放在drawable中的声音图片是以v+数字格式的

int resId = mContext.getResources().getIdentifier("v" + level, "drawable", mContext.getPackageName());

mVoice.setImageResource(resId);

}

}

}

—-声音播放工具类——

/**

* @param

* @author ldm

* @description 播放声音工具类

* @time 2016/6/25 11:29

*/

public class MediaPlayerManager {

//播放音频API类:MediaPlayer

private static MediaPlayer mMediaPlayer;

//是否暂停

private static boolean isPause;

/**

* @param

* filePath:文件路径

* onCompletionListener:播放完成监听

* @description 播放声音

* @author ldm

* @time 2016/6/25 11:30

*/

public static void playSound(String filePath, MediaPlayer.OnCompletionListener onCompletionListener) {

if (mMediaPlayer == null) {

mMediaPlayer = new MediaPlayer();

//设置一个error监听器

mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {

public boolean onError(MediaPlayer arg0, int arg1, int arg2) {

mMediaPlayer.reset();

return false;

}

});

} else {

mMediaPlayer.reset();

}

try {

mMediaPlayer.setAudioStreamType(android.media.AudioManager.STREAM_MUSIC);

mMediaPlayer.setOnCompletionListener(onCompletionListener);

mMediaPlayer.setDataSource(filePath);

mMediaPlayer.prepare();

mMediaPlayer.start();

} catch (Exception e) {

}

}

/**

* @param

* @description 暂停播放

* @author ldm

* @time 2016/6/25 11:31

*/

public static void pause() {

if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { //正在播放的时候

mMediaPlayer.pause();

isPause = true;

}

}

/**

* @param

* @description 重新播放

* @author ldm

* @time 2016/6/25 11:31

*/

public static void resume() {

if (mMediaPlayer != null && isPause) {

mMediaPlayer.start();

isPause = false;

}

}

/**

* @param

* @description 释放操作

* @author ldm

* @time 2016/6/25 11:32

*/

public static void release() {

if (mMediaPlayer != null) {

mMediaPlayer.release();

mMediaPlayer = null;

}

}

—–录音操作工具类—–

/**

* @param

* @author ldm

* @description 录音管理工具类

* @time 2016/6/25 9:39

*/

public class AudioManager {

//AudioRecord: 主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理。

// 优点:可以语音实时处理,可以实现各种音频的封装

private MediaRecorder mMediaRecorder;

//录音文件

private String mDir;

//当前录音文件目录

private String mCurrentFilePath;

//单例模式

private static AudioManager mInstance;

//是否准备好

private boolean isPrepare;

//私有构造方法

private AudioManager(String dir) {

mDir = dir;

}

//对外公布获取实例的方法

public static AudioManager getInstance(String dir) {

if (mInstance == null) {

synchronized (AudioManager.class) {

if (mInstance == null) {

mInstance = new AudioManager(dir);

}

}

}

return mInstance;

}

/**

* @param

* @author ldm

* @description 录音准备工作完成回调接口

* @time 2016/6/25 11:14

*/

public interface AudioStateListener {

void wellPrepared();

}

public AudioStateListener mAudioStateListener;

/**

* @param

* @description 供外部类调用的设置回调方法

* @author ldm

* @time 2016/6/25 11:14

*/

public void setOnAudioStateListener(AudioStateListener listener) {

mAudioStateListener = listener;

}

/**

* @param

* @description 录音准备工作

* @author ldm

* @time 2016/6/25 11:15

*/

public void prepareAudio() {

try {

isPrepare = false;

File dir = new File(mDir);

if (!dir.exists()) {

dir.mkdirs();//文件不存在,则创建文件

}

String fileName = generateFileName();

File file = new File(dir, fileName);

mCurrentFilePath = file.getAbsolutePath();

mMediaRecorder = new MediaRecorder();

// 设置输出文件路径

mMediaRecorder.setOutputFile(file.getAbsolutePath());

// 设置MediaRecorder的音频源为麦克风

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

// 设置音频格式为RAW_AMR

mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);

// 设置音频编码为AMR_NB

mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

// 准备录音

mMediaRecorder.prepare();

// 开始,必需在prepare()后调用

mMediaRecorder.start();

// 准备完成

isPrepare = true;

if (mAudioStateListener != null) {

mAudioStateListener.wellPrepared();

}

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* @param

* @description 随机生成录音文件名称

* @author ldm

* @time 2016/6/25 、

*/

private String generateFileName() {

//随机生成不同的UUID

return UUID.randomUUID().toString() + ".amr";

}

/**

* @param

* @description 获取音量值

* @author ldm

* @time 2016/6/25 9:49

*/

public int getVoiceLevel(int maxlevel) {

if (isPrepare) {

try {

// getMaxAmplitude返回的数值最大是32767

return maxlevel * mMediaRecorder.getMaxAmplitude() / 32768 + 1;//返回结果1-7之间

} catch (Exception e) {

e.printStackTrace();

}

}

return 1;

}

/**

* @param

* @description 释放资源

* @author ldm

* @time 2016/6/25 9:50

*/

public void release() {

mMediaRecorder.stop();

mMediaRecorder.reset();

mMediaRecorder = null;

}

/**

* @param

* @description 录音取消

* @author ldm

* @time 2016/6/25 9:51

*/

public void cancel() {

release();

if (mCurrentFilePath != null) {

//取消录音后删除对应文件

File file = new File(mCurrentFilePath);

file.delete();

mCurrentFilePath = null;

}

}

/**

* @param

* @description 获取当前文件路径

* @author ldm

* @time 2016/6/25 9:51

*/

public String getCurrentFilePath() {

return mCurrentFilePath;

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

Android仿微信视频聊天窗口,Android仿微信语音聊天界面设计相关推荐

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

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

  2. Android仿微信气泡聊天界面设计

    Android仿微信气泡聊天界面设计 微信的气泡聊天是仿iPhone自带短信而设计出来的,不过感觉还不错可以尝试一下仿着微信的气泡聊天做一个Demo,给大家分享一下!效果图如下: 气泡聊天最终要的是素 ...

  3. 转-Android仿微信气泡聊天界面设计

    微信的气泡聊天是仿iPhone自带短信而设计出来的,不过感觉还不错可以尝试一下仿着微信的气泡聊天做一个Demo,给大家分享一下!效果图如下: 气泡聊天最终要的是素材,要用到9.png文件的素材,这样气 ...

  4. 微信视频号Android面试经验,如何通过视频面试拿下offer?我们来给你支招啦!

    原标题:如何通过视频面试拿下offer?我们来给你支招啦! 香港留学的面试有好几种常见方式,包括有亲身到学校现场面试.Skype视频面试.QQ视频面试和微信视频面试等.这段时间迎来了香港留学的申请高峰 ...

  5. html怎么实现聊天界面设计,纯css制作仿微信聊天页面

    纯css制作仿微信聊天页面 *{ margin: 0; padding: 0; } body{ font-size: 14px; } .triangle{ margin: 100px auto ; w ...

  6. 如何保存微信视频到本地,微信朋友圈怎么发本地的视频。

    如何保存微信视频到本地 首先要找到你的文件浏览器,就是浏览文件夹的工具. 微信小视频默认保存路径sdcard0/Tencent/MicroMsg/最长后缀名称文件夹/video 可以在文件夹工具搜索 ...

  7. 手机端语音聊天界面微信公众号版

    下载地址 原创(不支持IOS)由于上一个发布的项目在IOS不支持录音接口的调用,所以写了个微信公众号版的,通过调用微信SDK下的录音接口,实现语音聊天功能. 配置在common/config.js文件 ...

  8. 腾讯云实时音视频带你玩转语音聊天室

    声音交友,在线K歌,自由上麦,声波传达-- 从最初单一的一对一语音通话,到后来火爆的多人语音群聊,再到现在聚集了一批"音控"的纯语音聊天室,当代年轻人的社交APP里最不可少的功能就 ...

  9. 仿android微信视频编辑,Android 仿微信短视频录制

    VideoRecorder Android 仿微信短视频录制 预览 Bug 修复与更新日志: 更新日志: 1.2.0:仿照微信,短按拍照长按拍摄 --19.06.21 1.1.5:增加进度条,修改依赖 ...

  10. android微信视频查看源代码,Android仿微信视频拍摄UI, 基于ffmpeg的视频录制编辑

    功能主要包含5点: 1.基于ffmpeg的视频拍摄及合成; 2.自定义拍摄按钮, 长按放大并且显示拍摄进度; 3.自定义view, 实现手绘涂鸦; 4.自定义可触摸旋转缩放位移的表情文字view; 5 ...

最新文章

  1. mysql for循环_基于Swoole扩展开发异步高性能的MySQL代理服务器
  2. mysql 5.7 缺点_MySQL · 特性分析 · MySQL 5.7 外部XA Replication实现及缺陷分析
  3. 吴敏霞(为奥运冠军名字作诗)
  4. Django 2.1.3 中间件使用
  5. |NOIOJ|动态规划|3532:最大上升子序列和
  6. 基于redis分布式锁实现的多线程并发程序
  7. [资源分享] 吴恩达最新《机器学习训练秘籍》中文版可以免费下载了
  8. debian 升级linux内核,Debian8升级内核到4.5
  9. kalman滤波在雷达目标跟踪中的应用_简述Automotive radar中的多目标跟踪处理
  10. B75经典门户商业版discuz模板
  11. 30. 确保目标空间足够大
  12. 计算机图形学(二)——实验二:直线的生成算法
  13. React小书中得CommentList的需求实现
  14. 思维导图 XMind 闯关之路(第02关)插入各类符号
  15. JAVA实现战舰游戏
  16. 网络信息安全之零信任
  17. Python 发出警报声音 简单播放声音 beep 在linux 上
  18. 讲解双手白嫩光滑的几点小常识
  19. angular项目中使用Primeng
  20. 【浏览器兼容性】如何隐藏微软的ie和edge浏览器密码输入框的小眼睛

热门文章

  1. McAfee设置信任文件
  2. verbose=False(TensorFlow)
  3. TP50 TP90 TP99 TP999 详细说明
  4. 数码相机与手机相机成像差别
  5. Struck的安装注意事项
  6. 2021有效的电子邮箱号码大全,外贸企业邮箱地址大全
  7. Qt之动态属性unpolish()和polish()
  8. linux wifi驱动开发 二,Linux 下wifi 驱动开发(二)—— WiFi模块浅析
  9. 零基础学UI设计难吗?
  10. 有关HTML的小众面试题