Android仿微信语音聊天界面设计
有段时间没有看视频了,昨天晚上抽了点空时间,又看了下鸿洋大神的视频教程,又抽时间写了个学习记录。代码和老师讲的基本一样,网上也有很多相同的博客。我只是在AndroidStudio环境下写的。
—-主界面代码——
publicclassMainActivityextendsActivity{
privateListViewmListView;
privateArrayAdapter<Recorder>mAdapter;
privateList<Recorder>mDatas=newArrayList<Recorder>();
privateAudioRecorderButtonmAudioRecorderButton;
privateViewanimView;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
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(newAudioRecorderButton.AudioFinishRecorderCallBack(){
publicvoidonFinish(floatseconds,StringfilePath){
Recorderrecorder=newRecorder(seconds,filePath);
mDatas.add(recorder);
//更新数据
mAdapter.notifyDataSetChanged();
//设置位置
mListView.setSelection(mDatas.size()-1);
}
});
mAdapter=newRecoderAdapter(this,mDatas);
mListView.setAdapter(mAdapter);
//listView的item点击事件
mListView.setOnItemClickListener(newOnItemClickListener(){
publicvoidonItemClick(AdapterView<?>arg0,Viewview,intposition,longid){
//声音播放动画
if(animView!=null){
animView.setBackgroundResource(R.drawable.adj);
animView=null;
}
animView=view.findViewById(R.id.id_recoder_anim);
animView.setBackgroundResource(R.drawable.play_anim);
AnimationDrawableanimation=(AnimationDrawable)animView.getBackground();
animation.start();
//播放录音
MediaPlayerManager.playSound(mDatas.get(position).filePath,newMediaPlayer.OnCompletionListener(){
publicvoidonCompletion(MediaPlayermp){
//播放完成后修改图片
animView.setBackgroundResource(R.drawable.adj);
}
});
}
});
}
@Override
protectedvoidonPause(){
super.onPause();
MediaPlayerManager.pause();
}
@Override
protectedvoidonResume(){
super.onResume();
MediaPlayerManager.resume();
}
@Override
protectedvoidonDestroy(){
super.onDestroy();
MediaPlayerManager.release();
}
—自定义Button——-
/**
*@param
*@authorldm
*@description自定义Button
*@time2016/6/259:26
*/
publicclassAudioRecorderButtonextendsButton{
//按钮正常状态(默认状态)
privatestaticfinalintSTATE_NORMAL=1;
//正在录音状态
privatestaticfinalintSTATE_RECORDING=2;
//录音取消状态
privatestaticfinalintSTATE_CANCEL=3;
//记录当前状态
privateintmCurrentState=STATE_NORMAL;
//是否开始录音标志
privatebooleanisRecording=false;
//判断在Button上滑动距离,以判断是否取消
privatestaticfinalintDISTANCE_Y_CANCEL=50;
//对话框管理工具类
privateDialogManagermDialogManager;
//录音管理工具类
privateAudioManagermAudioManager;
//记录录音时间
privatefloatmTime;
//是否触发longClick
privatebooleanmReady;
//录音准备
privatestaticfinalintMSG_AUDIO_PREPARED=0x110;
//音量发生改变
privatestaticfinalintMSG_VOICE_CHANGED=0x111;
//取消提示对话框
privatestaticfinalintMSG_DIALOG_DIMISS=0x112;
/**
*@description获取音量大小的线程
*@authorldm
*@time2016/6/259:30
*@param
*/
privateRunnablemGetVoiceLevelRunnable=newRunnable(){
publicvoidrun(){
while(isRecording){//判断正在录音
try{
Thread.sleep(100);
mTime+=0.1f;//录音时间计算
mHandler.sendEmptyMessage(MSG_VOICE_CHANGED);//每0.1秒发送消息
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
};
privateHandlermHandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
switch(msg.what){
caseMSG_AUDIO_PREPARED:
//显示对话框
mDialogManager.showRecordingDialog();
isRecording=true;
//开启一个线程计算录音时间
newThread(mGetVoiceLevelRunnable).start();
break;
caseMSG_VOICE_CHANGED:
//更新声音
mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));
break;
caseMSG_DIALOG_DIMISS:
//取消对话框
mDialogManager.dimissDialog();
break;
}
super.handleMessage(msg);
}
};
publicAudioRecorderButton(Contextcontext,AttributeSetattrs){
super(context,attrs);
mDialogManager=newDialogManager(context);
//录音文件存放地址
Stringdir=Environment.getExternalStorageDirectory()+"/ldm_voice";
mAudioManager=AudioManager.getInstance(dir);
mAudioManager.setOnAudioStateListener(newAudioManager.AudioStateListener(){
publicvoidwellPrepared(){
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
}
});
//由于这个类是button所以在构造方法中添加监听事件
setOnLongClickListener(newOnLongClickListener(){
publicbooleanonLongClick(Viewv){
mReady=true;
mAudioManager.prepareAudio();
returnfalse;
}
});
}
publicAudioRecorderButton(Contextcontext){
this(context,null);
}
/**
*@description录音完成后的回调
*@authorldm
*@time2016/6/2511:18
*@param
*/
publicinterfaceAudioFinishRecorderCallBack{
voidonFinish(floatseconds,StringfilePath);
}
privateAudioFinishRecorderCallBackfinishRecorderCallBack;
publicvoidsetFinishRecorderCallBack(AudioFinishRecorderCallBacklistener){
finishRecorderCallBack=listener;
}
/**
*@param
*@description处理Button的OnTouchEvent事件
*@authorldm
*@time2016/6/259:35
*/
@Override
publicbooleanonTouchEvent(MotionEventevent){
//获取TouchEvent状态
intaction=event.getAction();
//获得x轴坐标
intx=(int)event.getX();
//获得y轴坐标
inty=(int)event.getY();
switch(action){
caseMotionEvent.ACTION_DOWN://手指按下
changeState(STATE_RECORDING);
break;
caseMotionEvent.ACTION_MOVE://手指移动
if(isRecording){
//根据x,y的坐标判断是否需要取消
if(wantToCancle(x,y)){
changeState(STATE_CANCEL);
}else{
changeState(STATE_RECORDING);
}
}
break;
caseMotionEvent.ACTION_UP://手指放开
if(!mReady){
reset();
returnsuper.onTouchEvent(event);
}
if(!isRecording||mTime<0.6f){//如果时间少于0.6s,则提示录音过短
mDialogManager.tooShort();
mAudioManager.cancel();
//延迟显示对话框
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS,1000);
}elseif(mCurrentState==STATE_RECORDING){
//如果状态为正在录音,则结束录制
mDialogManager.dimissDialog();
mAudioManager.release();
if(finishRecorderCallBack!=null){
finishRecorderCallBack.onFinish(mTime,mAudioManager.getCurrentFilePath());
}
}elseif(mCurrentState==STATE_CANCEL){//想要取消
mDialogManager.dimissDialog();
mAudioManager.cancel();
}
reset();
break;
}
returnsuper.onTouchEvent(event);
}
/**
*恢复状态及标志位
*/
privatevoidreset(){
isRecording=false;
mTime=0;
mReady=false;
changeState(STATE_NORMAL);
}
privatebooleanwantToCancle(intx,inty){
//超过按钮的宽度
if(x<0||x>getWidth()){
returntrue;
}
//超过按钮的高度
if(y<-DISTANCE_Y_CANCEL||y>getHeight()+DISTANCE_Y_CANCEL){
returntrue;
}
returnfalse;
}
/**
*@param
*@description根据状态改变Button显示
*@authorldm
*@time2016/6/259:36
*/
privatevoidchangeState(intstate){
if(mCurrentState!=state){
mCurrentState=state;
switch(state){
caseSTATE_NORMAL:
setBackgroundResource(R.drawable.btn_recorder_normal);
setText(R.string.str_recorder_normal);
break;
caseSTATE_RECORDING:
setBackgroundResource(R.drawable.btn_recorder_recording);
setText(R.string.str_recorder_recording);
if(isRecording){
mDialogManager.recording();
}
break;
caseSTATE_CANCEL:
setBackgroundResource(R.drawable.btn_recorder_recording);
mDialogManager.wantToCancel();
setText(R.string.str_recorder_want_cancel);
break;
}
}
}
}
—-对话框管理工具类——
/**
*@description对话框管理工具类
*@authorldm
*@time2016/6/2511:53
*@param
*/
publicclassDialogManager{
//弹出对话框
privateDialogmDialog;
//录音图标
privateImageViewmIcon;
//音量显示图标
privateImageViewmVoice;
//对话框上提示文字
privateTextViewmLable;
//上下文对象
privateContextmContext;
publicDialogManager(Contextcontext){
this.mContext=context;
}
/**
*@param
*@description显示对话框
*@authorldm
*@time2016/6/259:56
*/
publicvoidshowRecordingDialog(){
//根据指定sytle实例化Dialog
mDialog=newDialog(mContext,R.style.AudioDialog);
LayoutInflaterinflater=LayoutInflater.from(mContext);
Viewview=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正在录音状态的对话框
*@authorldm
*@time2016/6/2510:08
*/
publicvoidrecording(){
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取消录音状态对话框
*@authorldm
*@time2016/6/2510:08
*/
publicvoidwantToCancel(){
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时间过短提示的对话框
*@authorldm
*@time2016/6/2510:09
*/
publicvoidtooShort(){
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
*@authorldm
*@time2016/6/25取消(关闭)对话框
*/
publicvoiddimissDialog(){
if(mDialog!=null&&mDialog.isShowing()){//显示状态
mDialog.dismiss();
mDialog=null;
}
}
//显示更新音量级别的对话框
publicvoidupdateVoiceLevel(intlevel){
if(mDialog!=null&&mDialog.isShowing()){//显示状态
mIcon.setVisibility(View.VISIBLE);
mVoice.setVisibility(View.VISIBLE);
mLable.setVisibility(View.VISIBLE);
//设置图片的id,我们放在drawable中的声音图片是以v+数字格式的
intresId=mContext.getResources().getIdentifier("v"+level,"drawable",mContext.getPackageName());
mVoice.setImageResource(resId);
}
}
}
—-声音播放工具类——
/**
*@param
*@authorldm
*@description播放声音工具类
*@time2016/6/2511:29
*/
publicclassMediaPlayerManager{
//播放音频API类:MediaPlayer
privatestaticMediaPlayermMediaPlayer;
//是否暂停
privatestaticbooleanisPause;
/**
*@param
*filePath:文件路径
*onCompletionListener:播放完成监听
*@description播放声音
*@authorldm
*@time2016/6/2511:30
*/
publicstaticvoidplaySound(StringfilePath,MediaPlayer.OnCompletionListeneronCompletionListener){
if(mMediaPlayer==null){
mMediaPlayer=newMediaPlayer();
//设置一个error监听器
mMediaPlayer.setOnErrorListener(newMediaPlayer.OnErrorListener(){
publicbooleanonError(MediaPlayerarg0,intarg1,intarg2){
mMediaPlayer.reset();
returnfalse;
}
});
}else{
mMediaPlayer.reset();
}
try{
mMediaPlayer.setAudioStreamType(android.media.AudioManager.STREAM_MUSIC);
mMediaPlayer.setOnCompletionListener(onCompletionListener);
mMediaPlayer.setDataSource(filePath);
mMediaPlayer.prepare();
mMediaPlayer.start();
}catch(Exceptione){
}
}
/**
*@param
*@description暂停播放
*@authorldm
*@time2016/6/2511:31
*/
publicstaticvoidpause(){
if(mMediaPlayer!=null&&mMediaPlayer.isPlaying()){//正在播放的时候
mMediaPlayer.pause();
isPause=true;
}
}
/**
*@param
*@description重新播放
*@authorldm
*@time2016/6/2511:31
*/
publicstaticvoidresume(){
if(mMediaPlayer!=null&&isPause){
mMediaPlayer.start();
isPause=false;
}
}
/**
*@param
*@description释放操作
*@authorldm
*@time2016/6/2511:32
*/
publicstaticvoidrelease(){
if(mMediaPlayer!=null){
mMediaPlayer.release();
mMediaPlayer=null;
}
}
—–录音操作工具类—–
/**
*@param
*@authorldm
*@description录音管理工具类
*@time2016/6/259:39
*/
publicclassAudioManager{
//AudioRecord:主要是实现边录边播(AudioRecord+AudioTrack)以及对音频的实时处理。
//优点:可以语音实时处理,可以实现各种音频的封装
privateMediaRecordermMediaRecorder;
//录音文件
privateStringmDir;
//当前录音文件目录
privateStringmCurrentFilePath;
//单例模式
privatestaticAudioManagermInstance;
//是否准备好
privatebooleanisPrepare;
//私有构造方法
privateAudioManager(Stringdir){
mDir=dir;
}
//对外公布获取实例的方法
publicstaticAudioManagergetInstance(Stringdir){
if(mInstance==null){
synchronized(AudioManager.class){
if(mInstance==null){
mInstance=newAudioManager(dir);
}
}
}
returnmInstance;
}
/**
*@param
*@authorldm
*@description录音准备工作完成回调接口
*@time2016/6/2511:14
*/
publicinterfaceAudioStateListener{
voidwellPrepared();
}
publicAudioStateListenermAudioStateListener;
/**
*@param
*@description供外部类调用的设置回调方法
*@authorldm
*@time2016/6/2511:14
*/
publicvoidsetOnAudioStateListener(AudioStateListenerlistener){
mAudioStateListener=listener;
}
/**
*@param
*@description录音准备工作
*@authorldm
*@time2016/6/2511:15
*/
publicvoidprepareAudio(){
try{
isPrepare=false;
Filedir=newFile(mDir);
if(!dir.exists()){
dir.mkdirs();//文件不存在,则创建文件
}
StringfileName=generateFileName();
Filefile=newFile(dir,fileName);
mCurrentFilePath=file.getAbsolutePath();
mMediaRecorder=newMediaRecorder();
//设置输出文件路径
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(Exceptione){
e.printStackTrace();
}
}
/**
*@param
*@description随机生成录音文件名称
*@authorldm
*@time2016/6/25、
*/
privateStringgenerateFileName(){
//随机生成不同的UUID
returnUUID.randomUUID().toString()+".amr";
}
/**
*@param
*@description获取音量值
*@authorldm
*@time2016/6/259:49
*/
publicintgetVoiceLevel(intmaxlevel){
if(isPrepare){
try{
//getMaxAmplitude返回的数值最大是32767
returnmaxlevel*mMediaRecorder.getMaxAmplitude()/32768+1;//返回结果1-7之间
}catch(Exceptione){
e.printStackTrace();
}
}
return1;
}
/**
*@param
*@description释放资源
*@authorldm
*@time2016/6/259:50
*/
publicvoidrelease(){
mMediaRecorder.stop();
mMediaRecorder.reset();
mMediaRecorder=null;
}
/**
*@param
*@description录音取消
*@authorldm
*@time2016/6/259:51
*/
publicvoidcancel(){
release();
if(mCurrentFilePath!=null){
//取消录音后删除对应文件
Filefile=newFile(mCurrentFilePath);
file.delete();
mCurrentFilePath=null;
}
}
/**
*@param
*@description获取当前文件路径
*@authorldm
*@time2016/6/259:51
*/
publicStringgetCurrentFilePath(){
returnmCurrentFilePath;
}
}
代码中有注释,就不贴图了,和微信语音聊天界面一样的,所以叫仿微信嘛,呵呵。运行了也可以看到效果。所有代码可以从这里下载:http://xiazai.jb51.net/201611/yuanma/AndroidWXchat(jb51.net).rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。