日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android仿微信录音功能,自定义控件的设计技巧

發布時間:2024/3/26 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android仿微信录音功能,自定义控件的设计技巧 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

????????歡迎各位加入我的Android開發群[257053751]

最近由于需要做一個錄音功能(/噓 悄悄透露一下,千萬別告訴紅薯,就是新版本的OSC客戶端噢),起初打算采用仿微信的錄音方式,最后又改成了QQ的錄音方式,之前的微信錄音控件也就白寫了[大哭]。之前有很多朋友在問我自定義控件應該怎么學習,遂正好拿出來講講嘍,沒來得及截效果圖,大家就自己腦補一下微信發語音時的樣子吧。

????所謂自定義控件其實就是由于系統SDK無法完成需要的功能時,通過自己擴展系統組件達到完成所需功能做出的控件。

????Android自定義控件有兩種實現方式,一種是通過繼承View類,其中的全部界面通過畫布和畫筆自己創建,這種控件一般多用于游戲開發中;另一種則是通過繼承已有控件,或采用包含關系包含一個系統控件達到目的,這也是接下來本文所要講到的方法。

????先看代碼(篇幅有限,僅保留重要方法)

/*** 錄音專用Button,可彈出自定義的錄音dialog。需要配合{@link #RecordButtonUtil}使用* @author kymjs(kymjs123@gmail.com)*/ public class RecordButton extends Button {private static final int MIN_INTERVAL_TIME = 700; // 錄音最短時間private static final int MAX_INTERVAL_TIME = 60000; // 錄音最長時間private RecordButtonUtil mAudioUtil;private Handler mVolumeHandler; // 用于更新錄音音量大小的圖片public RecordButton(Context context) {super(context);mVolumeHandler = new ShowVolumeHandler(this);mAudioUtil = new RecordButtonUtil();initSavePath();}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (mAudioFile == null) {return false;}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:initlization();break;case MotionEvent.ACTION_UP:if (event.getY() < -50) {cancelRecord();} else {finishRecord();}break;case MotionEvent.ACTION_MOVE://做一些UI提示break;}return true;}/** 初始化 dialog和錄音器 */private void initlization() {mStartTime = System.currentTimeMillis();if (mRecordDialog == null) {mRecordDialog = new Dialog(getContext());mRecordDialog.setOnDismissListener(onDismiss);}mRecordDialog.show();startRecording();}/** 錄音完成(達到最長時間或用戶決定錄音完成) */private void finishRecord() {stopRecording();mRecordDialog.dismiss();long intervalTime = System.currentTimeMillis() - mStartTime;if (intervalTime < MIN_INTERVAL_TIME) {AppContext.showToastShort(R.string.record_sound_short);File file = new File(mAudioFile);file.delete();return;}if (mFinishedListerer != null) {mFinishedListerer.onFinishedRecord(mAudioFile,(int) ((System.currentTimeMillis() - mStartTime) / 1000));}}// 用戶手動取消錄音private void cancelRecord() {stopRecording();mRecordDialog.dismiss();File file = new File(mAudioFile);file.delete();if (mFinishedListerer != null) {mFinishedListerer.onCancleRecord();}}// 開始錄音private void startRecording() {mAudioUtil.setAudioPath(mAudioFile);mAudioUtil.recordAudio();mThread = new ObtainDecibelThread();mThread.start();}// 停止錄音private void stopRecording() {if (mThread != null) {mThread.exit();mThread = null;}if (mAudioUtil != null) {mAudioUtil.stopRecord();}}/******************************* inner class ****************************************/private class ObtainDecibelThread extends Thread {private volatile boolean running = true;public void exit() {running = false;}@Overridepublic void run() {while (running) {try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}if (System.currentTimeMillis() - mStartTime >= MAX_INTERVAL_TIME) {// 如果超過最長錄音時間mVolumeHandler.sendEmptyMessage(-1);}if (mAudioUtil != null && running) {// 如果用戶仍在錄音int volumn = mAudioUtil.getVolumn();if (volumn != 0)mVolumeHandler.sendEmptyMessage(volumn);} else {exit();}}}}private final OnDismissListener onDismiss = new OnDismissListener() {@Overridepublic void onDismiss(DialogInterface dialog) {stopRecording();}};static class ShowVolumeHandler extends Handler {private final WeakReference<RecordButton> mOuterInstance;public ShowVolumeHandler(RecordButton outer) {mOuterInstance = new WeakReference<RecordButton>(outer);}@Overridepublic void handleMessage(Message msg) {RecordButton outerButton = mOuterInstance.get();if (msg.what != -1) {// 大于0時 表示當前錄音的音量if (outerButton.mVolumeListener != null) {outerButton.mVolumeListener.onVolumeChange(mRecordDialog,msg.what);}} else {// -1 時表示錄音超時outerButton.finishRecord();}}}/** 音量改變的監聽器 */public interface OnVolumeChangeListener {void onVolumeChange(Dialog dialog, int volume);}public interface OnFinishedRecordListener {/** 用戶手動取消 */public void onCancleRecord();/** 錄音完成 */public void onFinishedRecord(String audioPath, int recordTime);} }

/*** {@link #RecordButton}需要的工具類* * @author kymjs(kymjs123@gmail.com)*/ public class RecordButtonUtil {public static final String AUDOI_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/oschina/audio"; // 錄音音頻保存根路徑private String mAudioPath; // 要播放的聲音的路徑private boolean mIsRecording;// 是否正在錄音private boolean mIsPlaying;// 是否正在播放private OnPlayListener listener;// 初始化 錄音器private void initRecorder() {mRecorder = new MediaRecorder();mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);mRecorder.setOutputFile(mAudioPath);mIsRecording = true;}/** 開始錄音,并保存到文件中 */public void recordAudio() {initRecorder();try {mRecorder.prepare();} catch (IOException e) {e.printStackTrace();}mRecorder.start();}/** 獲取音量值,只是針對錄音音量 */public int getVolumn() {int volumn = 0;// 錄音if (mRecorder != null && mIsRecording) {volumn = mRecorder.getMaxAmplitude();if (volumn != 0)volumn = (int) (10 * Math.log(volumn) / Math.log(10)) / 7;}return volumn;}/** 停止錄音 */public void stopRecord() {if (mRecorder != null) {mRecorder.stop();mRecorder.release();mRecorder = null;mIsRecording = false;}}public void startPlay(String audioPath) {if (!mIsPlaying) {if (!StringUtils.isEmpty(audioPath)) {mPlayer = new MediaPlayer();try {mPlayer.setDataSource(audioPath);mPlayer.prepare();mPlayer.start();if (listener != null) {listener.starPlay();}mIsPlaying = true;mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {if (listener != null) {listener.stopPlay();}mp.release();mPlayer = null;mIsPlaying = false;}});} catch (Exception e) {e.printStackTrace();}} else {AppContext.showToastShort(R.string.record_sound_notfound);}} // end playing}public interface OnPlayListener {/** 播放聲音結束時調用 */void stopPlay();/** 播放聲音開始時調用 */void starPlay();} }

????作為控件界面控制邏輯,我們主要看一下onTouchEvent方法:當手指按下的時候,初始化錄音器。手指在屏幕上移動的時候如果滑到按鈕之上的時候,event.getY會返回一個負值(因為滑出控件了嘛)。這里我寫的是-50主要是為了多一點緩沖,防止誤操作。

public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:initlization();break;case MotionEvent.ACTION_UP:if (mIsCancel && event.getY() < -50) {cancelRecord();} else {finishRecord();}mIsCancel = false;break;case MotionEvent.ACTION_MOVE:// 當手指移動到view外面,會cancel//做一些UI提示break;}return true;}

????一些設計技巧:比如通過回調解耦,使控件變得通用。雖說自定義控件一般不需要多么的通用,但是像錄音控件這種很多應用都會用到的功能,還是做得通用一點要好。像錄音時彈出的dialog,我采用從外部獲取的方式,方便以后修改這個彈窗,也方便代碼閱讀的時候更加清晰。再比如根據話筒音量改變錄音圖標這樣的方法,設置成外部以后,就算以后更換其他圖片,更換其他顯示方式,對自定義控件本身來說,不需要改任何代碼。

????對于錄音和放音的功能實現,采用包含關系單獨寫在一個新類里面,這樣方便以后做更多擴展,比如未來采用私有的錄音編碼加密,比如播放錄音之前先放一段音樂(誰特么這么無聊)等等。。。

????再來看一下Thread與Handle的交互,這里我設計的并不是很好,其實不應該將兩種消息放在同一個msg中發出的,這里主要是考慮到消息簡單,使用一個空msg僅僅通過一個int值區分信息就行了。

????Handle中采用了一個軟引用包含外部類,這種方式在網上有很多講解,之后我也會單獨再寫一篇博客講解,這里大家知道目的是為了防止對象間的互相引用造成內存泄露就可以了。

????以上便是對仿微信錄音界面的一個講解,其實微信的錄音效果實現起來比起QQ的效果還是比較簡單的,以后我也會再講QQ錄音控件的實現方法。

版權聲明:本文為博主原創文章,未經博主允許不得轉載。

轉載于:https://my.oschina.net/kjframe/blog/484884

總結

以上是生活随笔為你收集整理的Android仿微信录音功能,自定义控件的设计技巧的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久不射影院 | 国家队动漫免费观看在线观看晨光 | 丰满雪白极品少妇流白浆 | 成人性视频在线 | 国产男男gay体育生白袜 | 福利在线一区二区三区 | 在线成人中文字幕 | 韩国视频一区二区 | 成人快手免费看片 | 青春草网站 | av夜夜操 | 天堂国产一区二区三区 | 污污网站在线看 | 国产精品免费一区二区三区四区 | 男人的天堂一区 | 中文字幕色站 | 潘金莲裸体一级淫片视频 | 日本在线观看一区二区三区 | 亚洲爽爽爽 | 日本不卡视频在线观看 | 精品国产露脸精彩对白 | 99久久久无码国产精品衣服 | 欧美做爰xxxⅹ性欧美大片 | 国产片高清在线观看 | 日本中文字幕在线播放 | va在线视频 | 色爱av综合网 | 亚洲国产av一区二区三区 | 特黄色一级片 | www久久久久久 | 性视频久久 | 精品国产乱码久久久久久1区二区 | 欧美色图另类 | 国产91国语对白在线 | 99久久综合国产精品二区 | 丰满大乳露双乳呻吟 | zjzjzjzjzj亚洲女人 | 日韩毛毛片 | 美女视频黄a视频全免费观看 | 亚洲码无人客一区二区三区 | 制服诱惑一区 | 精品一区中文字幕 | 天天摸日日 | 黄色成人在线网站 | 少妇2做爰bd在线意大利堕落 | 亚洲无套| 欧美激情亚洲色图 | 6090伦理 | 日本精品人妻无码免费大全 | 精品无码在线视频 | 鲁一鲁色一色 | 蜜臀久久99精品久久久 | 天堂а√在线中文在线新版 | 国产精品vip | √资源天堂中文在线视频 | 伊人网狼人 | 成年人在线视频免费观看 | 午夜视频在线免费播放 | 亚洲国产精品视频一区 | 伊人久久大香线蕉综合网站 | 少妇高清精品毛片在线视频 | 国产一区二区三区电影在线观看 | 久久精品国产清自在天天线 | 中字幕视频在线永久在线观看免费 | 精品无码久久久久久久 | 丝袜美女被c | 成人午夜淫片免费观看 | 美女十八毛片 | 中国美女洗澡免费看网站 | 欧美日韩精品免费 | 中文字幕区| 99热久久这里只有精品 | 中文字幕免费视频 | 欧美理论视频 | 成人国产精品视频 | 中文在线a∨在线 | 久久精品免费在线 | 国内精品视频在线观看 | 久久理论片 | 亚洲免费色视频 | 日韩av在线免费播放 | 碰在线视频 | 久久老司机 | 视频成人免费 | 一级黄色片毛片 | 永久免费不卡在线观看黄网站 | www.av免费| 操出白浆视频 | 中文在线a∨在线 | 亚洲熟女一区 | 精品一区二区不卡 | 亚洲综合婷婷久久 | 操你妹影院 | 天天爽天天爱 | 国模精品一区二区三区 | 毛片av网址 | 91伦理在线 | 国产91精品在线观看 | 深夜视频在线免费观看 |