其实我接触android时间也不是很久,但是发现android远远比我们想象的要有趣并且复杂很多,所以还是要多花点时间来写一写这些demo例子,这个程序是我从慕课网上学来的,因为毕竟要自己手写,才能体会到程序的完整性,所以我还是建议大家自己手写代码,大部分代码我已经添加了注释,如果有疑问,大家一起来讨论讨论。

效果图

主布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.weixin_record.MainActivity" ><ListViewandroid:id="@+id/listview"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:background="#ebebeb"android:divider="@null"android:dividerHeight="10dp" ></ListView><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" ><!-- minHeight消除主界面上的一些间距 --><com.nickming.view.AudioRecordButtonandroid:id="@+id/recordButton"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="7dp"android:layout_marginLeft="50dp"android:layout_marginRight="50dp"android:layout_marginTop="6dp"android:background="@drawable/button_recordnormal"android:gravity="center"android:minHeight="0dp"android:padding="5dp"android:text="@string/normal"android:textColor="#727272" ></com.nickming.view.AudioRecordButton><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="#ccc" /></FrameLayout></LinearLayout>

listview的item布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="60dp"android:layout_marginTop="5dp" ><ImageViewandroid:id="@+id/item_icon"android:layout_width="40dp"android:layout_height="40dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginRight="5dp"android:src="@drawable/icon" /><FrameLayoutandroid:id="@+id/recorder_length"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_toLeftOf="@id/item_icon"android:background="@drawable/chatto_bg_focused" ><View android:id="@+id/id_recorder_anim"android:layout_width="25dp"android:layout_height="25dp"android:layout_gravity="center_vertical|right"android:background="@drawable/adj"/></FrameLayout><TextView android:id="@+id/recorder_time"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginRight="3dp"android:layout_toLeftOf="@id/recorder_length"android:text=""android:textColor="#ff777777"/></RelativeLayout>

dialog的布局样式文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/dialog_loading_bg"android:gravity="center"android:orientation="vertical"android:padding="20dp"tools:context="com.example.weixin_record.MainActivity" ><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal" ><ImageViewandroid:id="@+id/dialog_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/recorder"android:visibility="visible" /><ImageViewandroid:id="@+id/dialog_voice"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/v1"android:visibility="visible" /></LinearLayout><TextViewandroid:id="@+id/recorder_dialogtext"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="@string/shouzhishanghua"android:textColor="#ffffffff" /></LinearLayout>

新建文件夹drawable,并创立这些自定义资源文件

button加载时样式的文件

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><solid android:color="#eeeeee" /> <!-- 背景色solid --><strokeandroid:width="1px"android:color="#9b9b9b" /> <!-- 边框设置 --><corners android:radius="3dp" /> <!-- 转角 --></shape>

button正常样式文件

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><solid android:color="#ffffff" /> <!-- 背景色solid --><strokeandroid:width="1px"android:color="#9b9b9b" /> <!-- 边框设置 --><corners android:radius="3dp" /> <!-- 转角 --></shape>

播放时的帧动画文件

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" ><itemandroid:drawable="@drawable/v_anim1"android:duration="300"></item><itemandroid:drawable="@drawable/v_anim2"android:duration="300"></item><itemandroid:drawable="@drawable/v_anim3"android:duration="300"></item></animation-list>

string.xml

<?xml version="1.0" encoding="utf-8"?>
<resources><string name="app_name">weixin_Record</string><string name="hello_world">Hello world!</string><string name="action_settings">Settings</string><string  name="normal">按住 说话</string><string  name="recording">松开 结束</string><string  name="want_to_cancle">松开手指,取消发送</string><string name="shouzhishanghua">手指上滑,取消发送</string><string name="tooshort">录音时间过短</string></resources>

style.xml,这个主要改变了对话框的样式

<resources xmlns:android="http://schemas.android.com/apk/res/android"><!--Base application theme, dependent on API level. This theme is replacedby AppBaseTheme from res/values-vXX/styles.xml on newer devices.--><style name="AppBaseTheme" parent="android:Theme.Light"><!--Theme customizations available in newer API levels can go inres/values-vXX/styles.xml, while customizations related tobackward-compatibility can go here.--></style><!-- Application theme. --><style name="AppTheme" parent="AppBaseTheme"><!-- All customizations that are NOT specific to a particular API-level can go here. --></style><!-- 设置弹出窗口的属性,frame叠加,isfloat是否浮动,tarnslucent是否半透明,dim是背景是否变暗 --><style name="Theme_audioDialog" parent="@android:style/Theme.Dialog"><item name="android:windowBackground">@android:color/transparent</item><item name="android:windowFrame">@null</item><item name="android:windowIsFloating">true</item><item name="android:windowIsTranslucent">true</item><item name="android:backgroundDimEnabled">false</item></style></resources>

对了,要记得在mainfest中添加几个权限

<uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

现在来写主要的几个类

AudioRecordButton.class

package com.nickming.view;import com.example.weixin_record.R;
import com.example.weixin_record.R.string;
import com.nickming.view.AudioManager.AudioStageListener;import android.R.bool;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;public class AudioRecordButton extends Button implements AudioStageListener {private static final int STATE_NORMAL = 1;private static final int STATE_RECORDING = 2;private static final int STATE_WANT_TO_CANCEL = 3;private static final int DISTANCE_Y_CANCEL = 50;private int mCurrentState = STATE_NORMAL;// 已经开始录音private boolean isRecording = false;private DialogManager mDialogManager;private AudioManager mAudioManager;private float mTime = 0;// 是否触发了onlongclick,准备好了private boolean mReady;/*** 先实现两个参数的构造方法,布局会默认引用这个构造方法, 用一个 构造参数的构造方法来引用这个方法 * @param context*/public AudioRecordButton(Context context) {this(context, null);// TODO Auto-generated constructor stub}public AudioRecordButton(Context context, AttributeSet attrs) {super(context, attrs);mDialogManager = new DialogManager(getContext());// 这里没有判断储存卡是否存在,有空要判断String dir = Environment.getExternalStorageDirectory()+ "/nickming_recorder_audios";mAudioManager = AudioManager.getInstance(dir);mAudioManager.setOnAudioStageListener(this);setOnLongClickListener(new OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {// TODO Auto-generated methodmReady = true;mAudioManager.prepareAudio();return false;}});// TODO Auto-generated constructor stub}/*** 录音完成后的回调,回调给activiy,可以获得mtime和文件的路径* @author nickming**/public interface AudioFinishRecorderListener{void onFinished(float seconds,String filePath);}private AudioFinishRecorderListener mListener;public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener){mListener=listener;}// 获取音量大小的runnableprivate Runnable mGetVoiceLevelRunnable = new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubwhile (isRecording) {try {Thread.sleep(100);mTime += 0.1f;mhandler.sendEmptyMessage(MSG_VOICE_CHANGE);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}};// 准备三个常量private static final int MSG_AUDIO_PREPARED = 0X110;private static final int MSG_VOICE_CHANGE = 0X111;private static final int MSG_DIALOG_DIMISS = 0X112;private Handler mhandler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case MSG_AUDIO_PREPARED:// 显示应该是在audio end prepare之后回调mDialogManager.showRecordingDialog();isRecording = true;new Thread(mGetVoiceLevelRunnable).start();// 需要开启一个线程来变换音量break;case MSG_VOICE_CHANGE:mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));break;case MSG_DIALOG_DIMISS:break;}};};// 在这里面发送一个handler的消息@Overridepublic void wellPrepared() {// TODO Auto-generated method stubmhandler.sendEmptyMessage(MSG_AUDIO_PREPARED);}/*** 直接复写这个监听函数*/@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubint action = event.getAction();int x = (int) event.getX();int y = (int) event.getY();switch (action) {case MotionEvent.ACTION_DOWN:changeState(STATE_RECORDING);break;case MotionEvent.ACTION_MOVE:if (isRecording) {// 根据x,y来判断用户是否想要取消if (wantToCancel(x, y)) {changeState(STATE_WANT_TO_CANCEL);} else {changeState(STATE_RECORDING);}}break;case MotionEvent.ACTION_UP:// 首先判断是否有触发onlongclick事件,没有的话直接返回resetif (!mReady) {reset();return super.onTouchEvent(event);}// 如果按的时间太短,还没准备好或者时间录制太短,就离开了,则显示这个dialogif (!isRecording || mTime < 0.6f) {mDialogManager.tooShort();mAudioManager.cancel();mhandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);// 持续1.3s} else if (mCurrentState == STATE_RECORDING) {//正常录制结束mDialogManager.dimissDialog();mAudioManager.release();// release释放一个mediarecorderif (mListener!=null) {// 并且callbackActivity,保存录音mListener.onFinished(mTime, mAudioManager.getCurrentFilePath());}} else if (mCurrentState == STATE_WANT_TO_CANCEL) {// cancelmAudioManager.cancel();mDialogManager.dimissDialog();}reset();// 恢复标志位break;}return super.onTouchEvent(event);}/*** 回复标志位以及状态*/private void reset() {// TODO Auto-generated method stubisRecording = false;changeState(STATE_NORMAL);mReady = false;mTime = 0;}private boolean wantToCancel(int x, int y) {// TODO Auto-generated method stubif (x < 0 || x > getWidth()) {// 判断是否在左边,右边,上边,下边return true;}if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {return true;}return false;}private void changeState(int state) {// TODO Auto-generated method stubif (mCurrentState != state) {mCurrentState = state;switch (mCurrentState) {case STATE_NORMAL:setBackgroundResource(R.drawable.button_recordnormal);setText(R.string.normal);break;case STATE_RECORDING:setBackgroundResource(R.drawable.button_recording);setText(R.string.recording);if (isRecording) {mDialogManager.recording();// 复写dialog.recording();}break;case STATE_WANT_TO_CANCEL:setBackgroundResource(R.drawable.button_recording);setText(R.string.want_to_cancle);// dialog want to cancelmDialogManager.wantToCancel();break;}}}@Overridepublic boolean onPreDraw() {// TODO Auto-generated method stubreturn false;}}

对话框的manager

DialogManager.class

package com.nickming.view;import com.example.weixin_record.R;import android.app.Dialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;public class DialogManager {/*** 以下为dialog的初始化控件,包括其中的布局文件*/private Dialog mDialog;private ImageView mIcon;private ImageView mVoice;private TextView mLable;private Context mContext;public DialogManager(Context context) {// TODO Auto-generated constructor stubmContext = context;}public void showRecordingDialog() {// TODO Auto-generated method stubmDialog = new Dialog(mContext,R.style.Theme_audioDialog);// 用layoutinflater来引用布局LayoutInflater inflater = LayoutInflater.from(mContext);View view = inflater.inflate(R.layout.dialog_manager, null);mDialog.setContentView(view);mIcon = (ImageView) mDialog.findViewById(R.id.dialog_icon);mVoice = (ImageView) mDialog.findViewById(R.id.dialog_voice);mLable = (TextView) mDialog.findViewById(R.id.recorder_dialogtext);mDialog.show();}/*** 设置正在录音时的dialog界面*/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(R.string.shouzhishanghua);}}/*** 取消界面*/public void wantToCancel() {// TODO Auto-generated method stubif (mDialog != null && mDialog.isShowing()) {mIcon.setVisibility(View.VISIBLE);mVoice.setVisibility(View.GONE);mLable.setVisibility(View.VISIBLE);mIcon.setImageResource(R.drawable.cancel);mLable.setText(R.string.want_to_cancle);}}// 时间过短public void tooShort() {// TODO Auto-generated method stubif (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(R.string.tooshort);}}// 隐藏dialogpublic void dimissDialog() {// TODO Auto-generated method stubif (mDialog != null && mDialog.isShowing()) {mDialog.dismiss();mDialog = null;}}public void updateVoiceLevel(int level) {// TODO Auto-generated method stubif (mDialog != null && mDialog.isShowing()) {//先不改变它的默认状态
//          mIcon.setVisibility(View.VISIBLE);
//          mVoice.setVisibility(View.VISIBLE);
//          mLable.setVisibility(View.VISIBLE);//通过level来找到图片的id,也可以用switch来寻址,但是代码可能会比较长int resId = mContext.getResources().getIdentifier("v" + level,"drawable", mContext.getPackageName());mVoice.setImageResource(resId);}}}

audioManager.class

package com.nickming.view;import java.io.File;
import java.io.IOException;
import java.util.UUID;import com.example.weixin_record.R.string;import android.media.MediaRecorder;public class AudioManager {private MediaRecorder mRecorder;private String mDirString;private String mCurrentFilePathString;private boolean isPrepared;// 是否准备好了/*** 单例化的方法 1 先声明一个static 类型的变量a 2 在声明默认的构造函数 3 再用public synchronized static* 类名 getInstance() { if(a==null) { a=new 类();} return a; } 或者用以下的方法*//*** 单例化这个类*/private static AudioManager mInstance;private AudioManager(String dir) {mDirString=dir;}public static AudioManager getInstance(String dir) {if (mInstance == null) {synchronized (AudioManager.class) {if (mInstance == null) {mInstance = new AudioManager(dir);}}}return mInstance;}/*** 回调函数,准备完毕,准备好后,button才会开始显示录音框* * @author nickming**/public interface AudioStageListener {void wellPrepared();}public AudioStageListener mListener;public void setOnAudioStageListener(AudioStageListener listener) {mListener = listener;}// 准备方法public void prepareAudio() {try {// 一开始应该是false的isPrepared = false;File dir = new File(mDirString);if (!dir.exists()) {dir.mkdirs();}String fileNameString = generalFileName();File file = new File(dir, fileNameString);mCurrentFilePathString = file.getAbsolutePath();mRecorder = new MediaRecorder();// 设置输出文件mRecorder.setOutputFile(file.getAbsolutePath());// 设置meidaRecorder的音频源是麦克风mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置文件音频的输出格式为amrmRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);// 设置音频的编码格式为amrmRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 严格遵守google官方api给出的mediaRecorder的状态流程图mRecorder.prepare();mRecorder.start();// 准备结束isPrepared = true;// 已经准备好了,可以录制了if (mListener != null) {mListener.wellPrepared();}} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/*** 随机生成文件的名称* * @return*/private String generalFileName() {// TODO Auto-generated method stubreturn UUID.randomUUID().toString() + ".amr";}// 获得声音的levelpublic int getVoiceLevel(int maxLevel) {// mRecorder.getMaxAmplitude()这个是音频的振幅范围,值域是1-32767if (isPrepared) {try {// 取证+1,否则去不到7return maxLevel * mRecorder.getMaxAmplitude() / 32768 + 1;} catch (Exception e) {// TODO Auto-generated catch block}}return 1;}// 释放资源public void release() {// 严格按照api流程进行mRecorder.stop();mRecorder.release();mRecorder = null;}// 取消,因为prepare时产生了一个文件,所以cancel方法应该要删除这个文件,// 这是与release的方法的区别public void cancel() {release();if (mCurrentFilePathString != null) {File file = new File(mCurrentFilePathString);file.delete();mCurrentFilePathString = null;}}public String getCurrentFilePath() {// TODO Auto-generated method stubreturn mCurrentFilePathString;}}

MediaManager.class

package com.example.weixin_record;import java.io.IOException;import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;public class MediaManager {private static MediaPlayer mPlayer;private static boolean isPause;public static  void playSound(String filePathString,OnCompletionListener onCompletionListener) {// TODO Auto-generated method stubif (mPlayer==null) {mPlayer=new MediaPlayer();//保险起见,设置报错监听mPlayer.setOnErrorListener(new OnErrorListener() {@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {// TODO Auto-generated method stubmPlayer.reset();return false;}});}else {mPlayer.reset();//就回复}try {mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mPlayer.setOnCompletionListener(onCompletionListener);mPlayer.setDataSource(filePathString);mPlayer.prepare();mPlayer.start();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalStateException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//停止函数public static void pause(){if (mPlayer!=null&&mPlayer.isPlaying()) {mPlayer.pause();isPause=true;}}//继续public static void resume(){if (mPlayer!=null&&isPause) {mPlayer.start();isPause=false;}}public  static void release(){if (mPlayer!=null) {mPlayer.release();mPlayer=null;}}
}

RecorderAdapter.class

package com.example.weixin_record;import java.util.List;import com.example.weixin_record.MainActivity.Recorder;import android.content.Context;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.TextView;public class RecorderAdapter extends ArrayAdapter<Recorder> {private LayoutInflater inflater;private int mMinItemWith;// 设置对话框的最大宽度和最小宽度private int mMaxItemWith;public RecorderAdapter(Context context, List<Recorder> dataList) {super(context, -1, dataList);// TODO Auto-generated constructor stubinflater = LayoutInflater.from(context);// 获取系统宽度WindowManager wManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wManager.getDefaultDisplay().getMetrics(outMetrics);mMaxItemWith = (int) (outMetrics.widthPixels * 0.7f);mMinItemWith = (int) (outMetrics.widthPixels * 0.15f);}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder = null;if (convertView == null) {convertView = inflater.inflate(R.layout.item_layout, parent, false);viewHolder=new ViewHolder();viewHolder.seconds=(TextView) convertView.findViewById(R.id.recorder_time);viewHolder.length=convertView.findViewById(R.id.recorder_length);convertView.setTag(viewHolder);}else {viewHolder=(ViewHolder) convertView.getTag();}viewHolder.seconds.setText(Math.round(getItem(position).time)+"\"");ViewGroup.LayoutParams lParams=viewHolder.length.getLayoutParams();lParams.width=(int) (mMinItemWith+mMaxItemWith/60f*getItem(position).time);viewHolder.length.setLayoutParams(lParams);return convertView;}class ViewHolder {TextView seconds;// 时间View length;// 对话框长度}}

MainActivity.class

package com.example.weixin_record;import java.util.ArrayList;
import java.util.List;import com.nickming.view.AudioRecordButton;
import com.nickming.view.AudioRecordButton.AudioFinishRecorderListener;import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;public class MainActivity extends Activity {AudioRecordButton button;private ListView mlistview;private ArrayAdapter<Recorder> mAdapter;private View viewanim;private List<Recorder> mDatas = new ArrayList<MainActivity.Recorder>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mlistview = (ListView) findViewById(R.id.listview);button = (AudioRecordButton) findViewById(R.id.recordButton);button.setAudioFinishRecorderListener(new AudioFinishRecorderListener() {@Overridepublic void onFinished(float seconds, String filePath) {// TODO Auto-generated method stubRecorder recorder = new Recorder(seconds, filePath);mDatas.add(recorder);mAdapter.notifyDataSetChanged();mlistview.setSelection(mDatas.size() - 1);}});mAdapter = new RecorderAdapter(this, mDatas);mlistview.setAdapter(mAdapter);mlistview.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {// TODO Auto-generated method stub// 播放动画if (viewanim!=null) {//让第二个播放的时候第一个停止播放viewanim.setBackgroundResource(R.id.id_recorder_anim);viewanim=null;}viewanim = view.findViewById(R.id.id_recorder_anim);viewanim.setBackgroundResource(R.drawable.play);AnimationDrawable drawable = (AnimationDrawable) viewanim.getBackground();drawable.start();// 播放音频MediaManager.playSound(mDatas.get(position).filePathString,new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {viewanim.setBackgroundResource(R.id.id_recorder_anim);}});}});}@Overrideprotected void onPause() {// TODO Auto-generated method stubsuper.onPause();MediaManager.pause();}@Overrideprotected void onResume() {// TODO Auto-generated method stubsuper.onResume();MediaManager.resume();}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();MediaManager.release();}class Recorder {float time;String filePathString;public Recorder(float time, String filePathString) {super();this.time = time;this.filePathString = filePathString;}public float getTime() {return time;}public void setTime(float time) {this.time = time;}public String getFilePathString() {return filePathString;}public void setFilePathString(String filePathString) {this.filePathString = filePathString;}}}

主要就是这几个类了,另外工程我已经上传到了csdn上了,有需要的朋友可以下载,看我上传的资源即可找到。

Android仿微信语音聊天demo相关推荐

  1. android 仿微信语音聊天

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

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

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

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

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

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

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

  5. Android仿微信语音聊天

    1.项目界面展示: 2.项目代码整体结构简析: (1)AudioRecorderButton类(录音按钮):State:STATE_NORMAL[正常状态].STATE_RECORDERING[正在录 ...

  6. Android 仿微信语音聊天,正式加入字节跳动

    /** 恢复标志位 */ private void resetState() { isRecording = false; isReady = false; changeState(STATE_NOR ...

  7. Android 仿微信语音聊天,flutter项目结构

    4.录音类里有两个成员:录音长度,录音路径. 下面贴一下代码: 自定义Button package com.zms.wechatrecorder.view; import com.zms.wechat ...

  8. java实现仿微信app聊天功能_Android仿微信语音聊天功能

    本文实例讲述了Android仿微信语音聊天功能代码.分享给大家供大家参考.具体如下: 项目效果如下: 具体代码如下: AudioManager.java package com.xuliugen.we ...

  9. android高仿微信聊天页面,Android 高仿微信语音聊天页面高斯模糊(毛玻璃效果)

    目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...

最新文章

  1. python需要变量命名规则_和孩子一起学习python之变量命名规则
  2. 微软超过苹果 成为全球第一大市值公司
  3. GeoTools——JTS空间操作
  4. 关于MYSQL中FLOAT和DOUBLE类型的存储
  5. Django组件 中间件
  6. HDU 3729【二分匹配】
  7. Java开发笔记(一百三十一)Swing的列表框
  8. 句子结构 ------中文句子结构分析
  9. 主数据系统的设计与实现
  10. 数据库delete不释放空间处理方法
  11. Android studio通过科大讯飞的SDK实现文字转语音功能
  12. 电商项目 Java还是Django_Django电商平台Saleor搭建初体验
  13. 已知含税单价、税率、数量,计算不含税单价、不含税金额、税额
  14. 机器学习读书笔记(四)朴素贝叶斯基础篇之网站账号分类
  15. 【北京-后厂村】大厂云集,精心筛选了19家公司推荐给你
  16. 【FPGA】串口以命令控制温度采集
  17. 专题总纲目录 管理类联考 MBA/MEM/MPA/MPACC总纲
  18. 【OJ每日一练】1199 - 计算并联电阻的阻值
  19. 使用phpMyAdmin修改数据库名称
  20. 用AI打破编解码器内卷,高通最新几篇顶会论文脑洞有点大

热门文章

  1. idea配置tomcat详细步骤
  2. 用于PassMark KeyboardTest 的ANSI 104 键盘布局
  3. 维度建模之 星型模型与雪花模型
  4. 电力系统自动装置课程设计——发电机励磁系统的数学模型及PID控制仿真
  5. NO.87 提前还款or买火鸡?(捎带举例JAVA Double精度计算问题)
  6. java-net-php-python-901ssm高校选用教材子系统ppt计算机毕业设计程序
  7. fcntl函数 和 ioctl函数
  8. 业务库数据入仓的策略
  9. 饿了吗 系统_跑外卖的奖励很高么,真的是这样吗?
  10. ettercap内网DNS劫持实验