模仿 微信 長按錄音 功能 實現
阿新 • • 發佈:2019-02-09
說明
最近參考別人程式碼自己模仿著寫了一個微信長按錄音的功能
效果圖
本來錄完的時候那個“我是時間”應該會變為具體的時間的,但是不知道我的360奇酷手機出了什麼毛病,一直不會改變,以及那個試聽的語音框其實可以根據時間長短改變長度的,但是這些在我手機上都不會發生。在別的測試機上都OK。
對360奇酷手機真是醉了,不知道他們把底層給改了多少東西,前一段時間我試驗5.0的新特性,它居然夠本能展現那些新特性。紅衣教主一直想把自己的手機往“安全”這方面發展,修改底層這麼多東西,是不是給開發者也帶來了很多困擾呢。
程式碼分析
我將程式碼重新整理改寫成了一個小Demo
這裡一共需要5個類
- Dialog管理類
這個類主要是用來建立一個Dialog,也就是錄音開始的時候顯示的那個Dialog,以及在不同的狀態時Dialog展現不同的內容。 - Audio管理類
這個類主要是開啟MediaRecorder以及管理MediaRecorder的。 - AudioRecordButton類
這個是自定義實現的Button類,繼承複寫了Button。 - Activity類
這個主要就是用來放內容的Activity了 - Media管理類
主要用來播放試聽已錄好的錄音
主要程式碼實現
- AudioRecordButton類
public AudioRecordButton (Context context) {
this(context, null);
}
public AudioRecordButton(final Context context, AttributeSet attrs) {
super(context, attrs);
mDialogManager = new DialogManager(context);
String dir = Environment.getExternalStorageDirectory() + "/recorder_audios";
mAudioManager = AudioManager.getInstance(dir);
mAudioManager.setOnAudioStageListener(new AudioManager.AudioStageListener() {
@Override
public void wellPrepared() {
//準備好了,傳送一個handler訊息
mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
}
});
setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mAudioManager.prepareAudio();
mReady = true;
//呼叫手機震動器短震
Vibrator vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
vibrator.vibrate(100);
return false;
}
});
}
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_CHANGE:
mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(7));
break;
case MSG_DIALOG_DISMISS:
break;
}
}
};
/**
* 錄音完成後進行回撥
*/
public interface AudioFinishRecorderListener {
/**
* 錄音成功後可以新增的事項
*
* @param seconds 錄音時間
* @param filePath 錄音路徑
*/
void onFinished(float seconds, String filePath);
}
private AudioFinishRecorderListener mListener;
public void setAudioFinishRecorderListener(AudioFinishRecorderListener listener) {
mListener = listener;
}
// 獲取音量大小的runnable
private Runnable mGetVoiceLevelRunnable = new Runnable() {
@Override
public void run() {
while (isRecording) {
try {
Thread.sleep(100);
mTime += 0.1f;
mHandler.sendEmptyMessage(MSG_VOICE_CHANGE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
@Override
public boolean onTouchEvent(MotionEvent event) {
int 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 (wantToChange(x, y)) {
changeState(STATE_WANT_TO_CANCEL);
} else {
changeState(STATE_RECORDING);
}
}
break;
case MotionEvent.ACTION_UP:
if (!mReady) {
reset();
return super.onTouchEvent(event);
}
// 如果按的時間太短,還沒準備好或者時間錄製太短,就離開了,則顯示這個dialog
if (!isRecording || mTime < 0.5f) {
mDialogManager.tooShort();
mAudioManager.cancel();
mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS, 1300);
} else if (mCurrentState == STATE_RECORDING) {//正常錄製結束
mDialogManager.dismissDialog();
mAudioManager.release();
if (mListener != null) {
mListener.onFinished(mTime, mAudioManager.getCurrentFilePath());
}
} else if (mCurrentState == STATE_WANT_TO_CANCEL) {
mAudioManager.cancel();
mDialogManager.dismissDialog();
}
reset();
break;
}
return super.onTouchEvent(event);
}
/*
恢復標誌位以及狀態
*/
private void reset() {
isRecording = false;
changeState(STATE_NORMAL);
mReady = false;
mTime = 0;
}
/*
發生什麼會取消傳送
*/
private boolean wantToChange(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;
}
private void changeState(int state) {
if (mCurrentState != state) {
mCurrentState = state;
switch (mCurrentState) {
case STATE_NORMAL:
setBackgroundResource(R.drawable.button_record_normal);
setText("按住 說話");
break;
case STATE_RECORDING:
setBackgroundResource(R.drawable.button_recording);
setText("鬆開 結束");
if (isRecording) {
mDialogManager.recording();
}
break;
case STATE_WANT_TO_CANCEL:
setBackgroundResource(R.drawable.button_recording);
setText("鬆開手指,取消傳送");
mDialogManager.wantToCancel();
break;
}
}
}