Android自定义UI实现微信语音
本文实例为大家分享了java获取不同路径的方法,供大家参考,具体内容如下
思路:
自定义button
获取dialogmanager、audiomanager setonlongclicklistener长按事件--做好audiomanager的录音准备工作
audiomanager.setonaudiostatelistener(this)实现录音准备完毕的接口回调方法,方法中去发送msg_audio_prepare消息代表录音准备工作完毕
在mhandler中接收消息,开始开启线程录音,并且计时,计时的过程中,去发送msg_voice_changed消息,去updatevoiceleve更新音量图标,另外在motionevent.action_up事件中,去定义audiofinishrecorderlistener.onfinish接口方法,方法是录音完毕的回调方法,在mainactivity中,maudiorecorderbutton.setaudiofinishrecorderlistener实现录音完毕回调方法去更新listviewui界面
点击listviewitem条目播放动画, mediamanager.playsound并且播放音频
activity_main.xml
<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.imooc_recorder.mainactivity" > <listview android:id="@+id/id_listview" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#ebebeb" android:divider="@null" android:dividerheight="10dp" > </listview> <framelayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <view android:background="#ccc" android:layout_width="fill_parent" android:layout_height="1dp" /> <com.example.recorder_view.audiorecorderbutton android:id="@+id/id_recorder_button" android:layout_width="fill_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_recorder_normal" android:gravity="center" android:minheight="0dp" android:padding="5dp" android:text="@string/str_recorder_nomal" android:textcolor="#727272" > </com.example.recorder_view.audiorecorderbutton> </framelayout> </linearlayout>
dialog_recorder.xml---dialog布局文件
<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:background="@drawable/dialog_loading_bg" android:gravity="center" android:orientation="vertical" android:padding="20dp" > <linearlayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <imageview android:id="@+id/id_recorder_dialog_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/recorder" android:visibility="visible" /> <imageview android:id="@+id/id_recorder_dialog_voice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/v1" android:visibility="visible" /> </linearlayout> <textview android:id="@+id/id_recorder_dialog_label" android:layout_margintop="5dp" android:text="手指上滑,取消发送" android:textcolor="#ffffff" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </linearlayout>
item_recorder.xml--listview中的每个item
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="#eeeeee" android:layout_height="60dp" android:layout_margintop="5dp" > <imageview android:id="@+id/id_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" /> <framelayout android:id="@+id/id_recorder_length" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centervertical="true" android:layout_toleftof="@id/id_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/id_recorder_time" android:layout_centervertical="true" android:layout_toleftof="@id/id_recorder_length" android:layout_marginright="3dp" android:textcolor="#ff777777" android:text="" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </relativelayout>
styles.xml
<style name="theme_audiodialog" parent="@android: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>
button_recorder_normal.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#ffffff"/> <stroke android:width="1px" android:color="#9b9b9b"/> <corners android:radius="3dp"/> </shape>
button_recorder_recording.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#ffffff"/> <stroke android:width="1px" android:color="#eeeeee"/> <corners android:radius="3dp"/> </shape>
play_anim.xml
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/v_anim1" android:duration="300"> </item> <item android:drawable="@drawable/v_anim2" android:duration="300"> </item> <item android:drawable="@drawable/v_anim3" android:duration="300"> </item> </animation-list>
mainactivity
package com.example.imooc_recorder; import java.util.arraylist; import java.util.list; import com.example.recorder_view.audiorecorderbutton; import com.example.recorder_view.audiorecorderbutton.audiofinishrecorderlistener; import com.example.recorder_view.mediamanager; import android.app.activity; import android.graphics.drawable.animationdrawable; import android.media.mediaplayer; import android.os.bundle; import android.view.menu; import android.view.menuitem; import android.view.view; import android.widget.adapterview.onitemclicklistener; import android.widget.adapterview; import android.widget.arrayadapter; import android.widget.listview; public class mainactivity extends activity { private listview mlistview; private arrayadapter<recorder> madapter; private list<recorder> mdatas = new arraylist<mainactivity.recorder>(); private audiorecorderbutton maudiorecorderbutton; private view animview; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mlistview = (listview) findviewbyid(r.id.id_listview); maudiorecorderbutton = (audiorecorderbutton) findviewbyid(r.id.id_recorder_button); //录音完毕,回调 maudiorecorderbutton.setaudiofinishrecorderlistener(new audiofinishrecorderlistener() { @override public void onfinish(float seconds, string filepath) { // todo auto-generated method stub recorder 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() { @override public void onitemclick(adapterview<?> parent, view view, int position, long id) { if (animview !=null) { animview.setbackgroundresource(r.drawable.adj); animview = null; } //播放动画 animview = view.findviewbyid(r.id.id_recorder_anim); animview.setbackgroundresource(r.drawable.play_anim); animationdrawable anim = (animationdrawable) animview.getbackground(); anim.start(); //播放音频 mediamanager.playsound(mdatas.get(position).filepath,new mediaplayer.oncompletionlistener() { @override public void oncompletion(mediaplayer mp) { // todo auto-generated method stub animview.setbackgroundresource(r.drawable.adj); } }); } }); } @override protected void onpause() { // todo auto-generated method stub super.onpause(); mediamanager.pause(); } @override protected void onresume() { // todo auto-generated method stub super.onresume(); mediamanager.resume(); } @override protected void ondestroy() { // todo auto-generated method stub super.ondestroy(); mediamanager.release(); } /**内部类*/ class recorder{ float time; string filepath; public recorder(float time, string filepath) { super(); this.time = time; this.filepath = filepath; } public float gettime() { return time; } public void settime(float time) { this.time = time; } public string getfilepath() { return filepath; } public void setfilepath(string filepath) { this.filepath = filepath; } } }
recorderadapter
package com.example.imooc_recorder; import java.util.list; import com.example.imooc_recorder.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.baseadapter; import android.widget.linearlayout; import android.widget.textview; public class recorderadapter extends arrayadapter<recorder> { // private list<recorder> mdatas; // private context mcontext; private int mminitemwidth; private int mmaxitemwidth; private layoutinflater minflater; public recorderadapter(context context, list<recorder> datas) { super(context, -1, datas); // mcontext = context; // mdatas = datas; windowmanager wm = (windowmanager) context .getsystemservice(context.window_service); displaymetrics outmetrics = new displaymetrics(); wm.getdefaultdisplay().getmetrics(outmetrics); mmaxitemwidth = (int) (outmetrics.widthpixels * 0.7f); mminitemwidth = (int) (outmetrics.widthpixels * 0.15f); minflater = layoutinflater.from(context); } @override public view getview(int position, view convertview, viewgroup parent) { // todo auto-generated method stub viewholder holder = null; if (convertview == null) { convertview = minflater.inflate(r.layout.item_recorder, parent, false); holder = new viewholder(); holder.seconds = (textview) convertview.findviewbyid(r.id.id_recorder_time); holder.length = convertview.findviewbyid(r.id.id_recorder_length); convertview.settag(holder); }else { holder = (viewholder) convertview.gettag(); } holder.seconds.settext(math.round(getitem(position).time)+"\""); viewgroup.layoutparams lp = holder.length.getlayoutparams(); lp.width = (int) (mminitemwidth +(mmaxitemwidth/60f*getitem(position).time)); return convertview; } private class viewholder { private textview seconds; private view length; } }
audiorecorderbutton
package com.example.recorder_view; import com.example.imooc_recorder.r; import com.example.recorder_view.audiomanager.audiostatelistener; import android.content.context; import android.os.environment; import android.os.handler; import android.telephony.signalstrength; import android.util.attributeset; import android.view.motionevent; import android.view.view; import android.widget.button; public class audiorecorderbutton extends button implements audiostatelistener { private static final int distance_y_cancel = 50; /** 提示框管理工具类 */ private dialogmanager mdialogmanager; /** 正常、松开手指取消发送、手指上滑取消发送 */ private static final int state_normal = 1; private static final int state_recording = 2; private static final int state_want_to_cancel = 3; /** 初始状态:正常 */ private int mcurstate = state_normal; /** 当前是否正在录音 */ private boolean isrecording = false; /** 录音工具类 */ private audiomanager maudiomanager; /** 录音总时间 */ private float mtime; /** 是否触发button */ private boolean mready; /** *****************自定义button************************************* */ public audiorecorderbutton(context context) { super(context); } public audiorecorderbutton(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); } public audiorecorderbutton(context context, attributeset attrs) { super(context, attrs); mdialogmanager = new dialogmanager(getcontext()); string dir = environment.getexternalstoragedirectory() + "/imooc_recorder_audios"; maudiomanager = audiomanager.getinstance(dir); maudiomanager.setonaudiostatelistener(this); /** 监听回调 */ setonlongclicklistener(new onlongclicklistener() { @override public boolean onlongclick(view v) { mready = true; // 录音准备--准备好后,有实现接口方法 maudiomanager.prepareandio(); return false; } }); } /****************************************************** * 完成录音准备的回调函数 */ @override public void wellprepared() { // 准备完毕,发送消息 mhandler.sendemptymessage(msg_audio_prepare); } private handler mhandler = new handler() { public void handlemessage(android.os.message msg) { switch (msg.what) { case msg_audio_prepare: mdialogmanager.showrecordingdailog(); isrecording = true; new thread(new runnable() { @override public void run() { // todo auto-generated method stub while (isrecording) { try { thread.sleep(100); // 录音计时 mtime += 0.1f; mhandler.sendemptymessage(msg_voice_changed); } catch (interruptedexception e) { e.printstacktrace(); } } } }).start(); break; case msg_voice_changed: mdialogmanager.updatevoiceleve(maudiomanager.getvoicelevel(7)); break; case msg_dialog_dimiss: mdialogmanager.dimissdailog(); break; default: break; } super.handlemessage(msg); }; }; private static final int msg_audio_prepare = 0x110; private static final int msg_voice_changed = 0x111; private static final int msg_dialog_dimiss = 0x112; @override public boolean ontouchevent(motionevent event) { // todo auto-generated method stub 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) { // 根据xy坐标。判断是否想要取消 if (wanttocancel(x, y)) { changestate(state_want_to_cancel); } else { changestate(state_recording); } } break; case motionevent.action_up: if (!mready) { // 没有触发onclick reset(); return super.ontouchevent(event); } if (!isrecording || mtime < 0.6f) { // prapred没有完成已经up了 mdialogmanager.tooshort(); maudiomanager.cancel(); mhandler.sendemptymessagedelayed(msg_dialog_dimiss, 1300); } else if (mcurstate == state_recording) { mdialogmanager.dimissdailog(); maudiomanager.release(); if (audiofinishrecorderlistener != null) { audiofinishrecorderlistener.onfinish(mtime, maudiomanager.getcurrentfilepath()); } } else if (mcurstate == state_want_to_cancel) { mdialogmanager.dimissdailog(); maudiomanager.cancel(); } // 恢复标志位 reset(); break; default: break; } return super.ontouchevent(event); } private void reset() { // todo auto-generated method stub mready = false; mtime = 0; isrecording = false; changestate(state_normal); } private boolean wanttocancel(int x, int y) { // x<0代表来到按钮的范围以外 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) { // todo auto-generated method stub if (mcurstate != state) { mcurstate = state; switch (state) { case state_normal: setbackgroundresource(r.drawable.button_recorder_normal); settext(r.string.str_recorder_nomal); break; case state_recording: setbackgroundresource(r.drawable.button_recorder_recording); settext(r.string.str_recorder_recording); if (isrecording) { // to do mdialogmanager.recording(); } break; case state_want_to_cancel: setbackgroundresource(r.drawable.button_recorder_recording); settext(r.string.str_recorder_want_cancel); mdialogmanager.wanttocancle(); break; default: break; } } } /** 完成录音回调 */ public interface audiofinishrecorderlistener { void onfinish(float seconds, string filepath); } private audiofinishrecorderlistener audiofinishrecorderlistener; public void setaudiofinishrecorderlistener( audiofinishrecorderlistener audiofinishrecorderlistener) { this.audiofinishrecorderlistener = audiofinishrecorderlistener; } }
dialogmanager
package com.example.recorder_view; import com.example.imooc_recorder.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 { private dialog mdialog; private imageview micon; private imageview mvoice; private textview mlabel; private context mcontext; public dialogmanager(context context) { this.mcontext = context; } public void showrecordingdailog() { mdialog = new dialog(mcontext, r.style.theme_audiodialog); layoutinflater inflater = layoutinflater.from(mcontext); view view = inflater.inflate(r.layout.dialog_recorder, null); mdialog.setcontentview(view); micon = (imageview) mdialog.findviewbyid(r.id.id_recorder_dialog_icon); mvoice = (imageview) mdialog .findviewbyid(r.id.id_recorder_dialog_voice); mlabel = (textview) mdialog.findviewbyid(r.id.id_recorder_dialog_label); mdialog.show(); } public void recording() { if (mdialog != null && mdialog.isshowing()) { micon.setvisibility(view.visible); mvoice.setvisibility(view.visible); mlabel.setvisibility(view.visible); micon.setimageresource(r.drawable.recorder); mlabel.settext("手指上滑,取消发送"); } } public void wanttocancle() { if (mdialog != null && mdialog.isshowing()) { micon.setvisibility(view.visible); mvoice.setvisibility(view.gone); mlabel.setvisibility(view.visible); micon.setimageresource(r.drawable.cancel); mlabel.settext("松开手指,取消发送"); } } public void tooshort() { if (mdialog != null && mdialog.isshowing()) { micon.setvisibility(view.visible); mvoice.setvisibility(view.gone); mlabel.setvisibility(view.visible); micon.setimageresource(r.drawable.voice_to_short); mlabel.settext("录音时间过短"); } } public void dimissdailog() { if (mdialog != null && mdialog.isshowing()) { mdialog.dismiss(); mdialog = null; } } public void updatevoiceleve(int level) { if (mdialog != null && mdialog.isshowing()) { // micon.setvisibility(view.visible); // mvoice.setvisibility(view.visible); // mlabel.setvisibility(view.visible); // 通过方法名字,找到资源 int resid = mcontext.getresources().getidentifier("v" + level, "drawable", mcontext.getpackagename()); mvoice.setimageresource(resid); } } }
audiomanager
package com.example.recorder_view; import java.io.file; import java.io.ioexception; import java.util.uuid; import javax.security.auth.privatecredentialpermission; import android.r.integer; import android.media.mediarecorder; public class audiomanager { private mediarecorder mmediarecorder; private string mdir; private string mcurrentfilepath; private static audiomanager minstance; private boolean isprepare; /** 接口回调 */ public interface audiostatelistener { void wellprepared(); } public audiostatelistener maudiostatelistener; public void setonaudiostatelistener(audiostatelistener audiostatelistener) { maudiostatelistener = audiostatelistener; } private audiomanager(string dir) { this.mdir = dir; } public static audiomanager getinstance(string dir) { if (minstance == null) { synchronized (audiomanager.class) { if (minstance == null) { minstance = new audiomanager(dir); } } } return minstance; } public void prepareandio() { isprepare = false; file dir = new file(mdir); if (!dir.exists()) { dir.mkdirs(); } string filename = genefilename(); file file = new file(dir, filename); mcurrentfilepath = file.getabsolutepath(); mmediarecorder = new mediarecorder(); // 设置输出文件 mmediarecorder.setoutputfile(file.getabsolutepath()); // 音频源头 mmediarecorder.setaudiosource(mediarecorder.audiosource.mic); // 设置音频格式 mmediarecorder.setoutputformat(mediarecorder.outputformat.raw_amr); // 设置音频编码 mmediarecorder.setaudioencoder(mediarecorder.audioencoder.amr_nb); try { mmediarecorder.prepare(); mmediarecorder.start(); isprepare = true; if (maudiostatelistener != null) { maudiostatelistener.wellprepared(); } } catch (exception e) { // todo auto-generated catch block e.printstacktrace(); } } private string genefilename() { return uuid.randomuuid().tostring() + ".amr"; } public int getvoicelevel(int maxlevel) { if (isprepare) { try { // mmediarecorder.getmaxamplitude() 1~32767 // return maxlevel*mmediarecorder.getmaxamplitude()/32768+1; return maxlevel * new mediarecorder().getmaxamplitude() / 32768 + 1; } catch (exception e) { } } return 1; } public void release() { mmediarecorder.release(); mmediarecorder = null; } public void cancel() { release(); if (mcurrentfilepath != null) { file file = new file(mcurrentfilepath); file.delete(); mcurrentfilepath = null; } } public string getcurrentfilepath() { // todo auto-generated method stub return mcurrentfilepath; } }
mediamanager
package com.example.recorder_view; 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 mediaplayer; private static boolean ispause; public static void playsound(string filepath, oncompletionlistener oncompletionlistener) { if (mediaplayer == null) { mediaplayer = new mediaplayer(); mediaplayer.setonerrorlistener(new onerrorlistener() { @override public boolean onerror(mediaplayer mp, int what, int extra) { mediaplayer.reset(); return false; } }); }else { mediaplayer.reset(); } try { mediaplayer.setaudiostreamtype(audiomanager.stream_music); mediaplayer.setoncompletionlistener(oncompletionlistener); mediaplayer.setdatasource(filepath); mediaplayer.prepare(); } catch (exception e) { e.printstacktrace(); } mediaplayer.start(); } public static void pause(){ if (mediaplayer!=null && mediaplayer.isplaying()) { mediaplayer.pause(); ispause = true; } } public static void resume(){ if (mediaplayer!=null && ispause) { mediaplayer.start(); ispause = false; } } public static void release(){ if (mediaplayer!=null) { mediaplayer.release(); mediaplayer = null; } } }
本文已被整理到了《android微信开发教程汇总》,欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Java判断时间段内文件是否更新的方法
下一篇: Asp.net防重复提交机制实现方法
推荐阅读
-
Android自定义UI实现微信语音
-
微信第三方登录Android实现代码
-
Android 微信小视频录制功能实现详细介绍
-
Android UI设计系列之自定义Dialog实现各种风格的对话框效果(7)
-
Android 微信摇一摇功能实现详细介绍
-
Android UI设计系列之自定义TextView属性实现带下划线的文本框(4)
-
Android UI设计系列之自定义SwitchButton开关实现类似IOS中UISwitch的动画效果(2)
-
Android UI设计系列之自定义DrawView组件实现数字签名效果(5)
-
android仿微信聊天界面 语音录制功能
-
Android实现使用微信登录第三方APP的方法