1. 程式人生 > >模仿 微信 長按錄音 功能 實現

模仿 微信 長按錄音 功能 實現

說明

最近參考別人程式碼自己模仿著寫了一個微信長按錄音的功能

效果圖

本來錄完的時候那個“我是時間”應該會變為具體的時間的,但是不知道我的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; } } }

專案託管(Github)