android仿微信聊天界面 语音录制功能
程序员文章站
2024-02-29 20:59:04
本例为模仿微信聊天界面ui设计,文字发送以及语言录制ui。
1先看效果图:
第一:chat.xml设计...
本例为模仿微信聊天界面ui设计,文字发送以及语言录制ui。
1先看效果图:
第一:chat.xml设计
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/chat_bg_default" > <!-- 标题栏 --> <relativelayout android:id="@+id/rl_layout" android:layout_width="fill_parent" android:layout_height="45dp" android:background="@drawable/title_bar" android:gravity="center_vertical" > <button android:id="@+id/btn_back" android:layout_width="70dp" android:layout_height="wrap_content" android:layout_centervertical="true" android:background="@drawable/title_btn_back" android:onclick="chat_back" android:text="返回" android:textcolor="#fff" android:textsize="14sp" /> <textview android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:text="白富美" android:textcolor="#ffffff" android:textsize="20sp" /> <imagebutton android:id="@+id/right_btn" android:layout_width="67dp" android:layout_height="wrap_content" android:layout_alignparentright="true" android:layout_centervertical="true" android:layout_marginright="5dp" android:background="@drawable/title_btn_right" android:src="@drawable/mm_title_btn_contact_normal" /> </relativelayout> <!-- 底部按钮以及 编辑框 --> <relativelayout android:id="@+id/rl_bottom" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignparentbottom="true" android:background="@drawable/chat_footer_bg" > <imageview android:id="@+id/ivpopup" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentleft="true" android:layout_centervertical="true" android:layout_marginleft="10dip" android:src="@drawable/chatting_setmode_msg_btn" /> <relativelayout android:id="@+id/btn_bottom" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignparentright="true" android:layout_centervertical="true" android:layout_torightof="@+id/ivpopup" > <button android:id="@+id/btn_send" android:layout_width="60dp" android:layout_height="40dp" android:layout_alignparentright="true" android:layout_centervertical="true" android:layout_marginright="10dp" android:background="@drawable/chat_send_btn" android:text="发送" /> <edittext android:id="@+id/et_sendmessage" android:layout_width="fill_parent" android:layout_height="40dp" android:layout_centervertical="true" android:layout_marginleft="10dp" android:layout_marginright="10dp" android:layout_toleftof="@id/btn_send" android:background="@drawable/login_edit_normal" android:singleline="true" android:textsize="18sp" /> </relativelayout> <textview android:id="@+id/btn_rcd" android:layout_width="fill_parent" android:layout_height="40dp" android:layout_alignparentright="true" android:layout_centervertical="true" android:layout_marginleft="10dp" android:layout_marginright="10dp" android:layout_torightof="@+id/ivpopup" android:background="@drawable/chat_send_btn" android:gravity="center" android:text="按住说话" android:visibility="gone" /> </relativelayout> <!-- 聊天内容 listview --> <listview android:id="@+id/listview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_above="@id/rl_bottom" android:layout_below="@id/rl_layout" android:cachecolorhint="#0000" android:divider="@null" android:dividerheight="5dp" android:scrollbarstyle="outsideoverlay" android:stackfrombottom="true" /> <!-- 录音显示ui层 --> <linearlayout android:id="@+id/rcchat_popup" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:visibility="gone" > <include android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" layout="@layout/voice_rcd_hint_window" /> </linearlayout> </relativelayout>
第二:语音录制类封装soundmeter.java
package com.example.voice_rcd; import java.io.ioexception; import android.media.mediarecorder; import android.os.environment; public class soundmeter { static final private double ema_filter = 0.6; private mediarecorder mrecorder = null; private double mema = 0.0; public void start(string name) { if (!environment.getexternalstoragestate().equals( android.os.environment.media_mounted)) { return; } if (mrecorder == null) { mrecorder = new mediarecorder(); mrecorder.setaudiosource(mediarecorder.audiosource.mic); mrecorder.setoutputformat(mediarecorder.outputformat.three_gpp); mrecorder.setaudioencoder(mediarecorder.audioencoder.amr_nb); mrecorder.setoutputfile(android.os.environment.getexternalstoragedirectory()+"/"+name); try { mrecorder.prepare(); mrecorder.start(); mema = 0.0; } catch (illegalstateexception e) { system.out.print(e.getmessage()); } catch (ioexception e) { system.out.print(e.getmessage()); } } } public void stop() { if (mrecorder != null) { mrecorder.stop(); mrecorder.release(); mrecorder = null; } } public void pause() { if (mrecorder != null) { mrecorder.stop(); } } public void start() { if (mrecorder != null) { mrecorder.start(); } } public double getamplitude() { if (mrecorder != null) return (mrecorder.getmaxamplitude() / 2700.0); else return 0; } public double getamplitudeema() { double amp = getamplitude(); mema = ema_filter * amp + (1.0 - ema_filter) * mema; return mema; } }
第三:主界面activity源码,没写太多解释,相对比较简单的自己研究下:
package com.example.voice_rcd; import java.io.file; import java.util.arraylist; import java.util.calendar; import java.util.list; import android.app.activity; import android.os.bundle; import android.os.environment; import android.os.handler; import android.os.systemclock; import android.view.motionevent; import android.view.view; import android.view.view.onclicklistener; import android.view.view.ontouchlistener; import android.view.windowmanager; import android.view.animation.animation; import android.view.animation.animationutils; import android.widget.button; import android.widget.edittext; import android.widget.imageview; import android.widget.linearlayout; import android.widget.listview; import android.widget.relativelayout; import android.widget.textview; import android.widget.toast; public class mainactivity extends activity implements onclicklistener { /** called when the activity is first created. */ private button mbtnsend; private textview mbtnrcd; private button mbtnback; private edittext medittextcontent; private relativelayout mbottom; private listview mlistview; private chatmsgviewadapter madapter; private list<chatmsgentity> mdataarrays = new arraylist<chatmsgentity>(); private boolean isshosrt = false; private linearlayout voice_rcd_hint_loading, voice_rcd_hint_rcding, voice_rcd_hint_tooshort; private imageview img1, sc_img1; private soundmeter msensor; private view rcchat_popup; private linearlayout del_re; private imageview chatting_mode_btn, volume; private boolean btn_vocie = false; private int flag = 1; private handler mhandler = new handler(); private string voicename; private long startvoicet, endvoicet; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.chat); // 启动activity时不自动弹出软键盘 getwindow().setsoftinputmode( windowmanager.layoutparams.soft_input_state_always_hidden); initview(); initdata(); } public void initview() { mlistview = (listview) findviewbyid(r.id.listview); mbtnsend = (button) findviewbyid(r.id.btn_send); mbtnrcd = (textview) findviewbyid(r.id.btn_rcd); mbtnsend.setonclicklistener(this); mbtnback = (button) findviewbyid(r.id.btn_back); mbottom = (relativelayout) findviewbyid(r.id.btn_bottom); mbtnback.setonclicklistener(this); chatting_mode_btn = (imageview) this.findviewbyid(r.id.ivpopup); volume = (imageview) this.findviewbyid(r.id.volume); rcchat_popup = this.findviewbyid(r.id.rcchat_popup); img1 = (imageview) this.findviewbyid(r.id.img1); sc_img1 = (imageview) this.findviewbyid(r.id.sc_img1); del_re = (linearlayout) this.findviewbyid(r.id.del_re); voice_rcd_hint_rcding = (linearlayout) this .findviewbyid(r.id.voice_rcd_hint_rcding); voice_rcd_hint_loading = (linearlayout) this .findviewbyid(r.id.voice_rcd_hint_loading); voice_rcd_hint_tooshort = (linearlayout) this .findviewbyid(r.id.voice_rcd_hint_tooshort); msensor = new soundmeter(); medittextcontent = (edittext) findviewbyid(r.id.et_sendmessage); //语音文字切换按钮 chatting_mode_btn.setonclicklistener(new onclicklistener() { public void onclick(view v) { if (btn_vocie) { mbtnrcd.setvisibility(view.gone); mbottom.setvisibility(view.visible); btn_vocie = false; chatting_mode_btn .setimageresource(r.drawable.chatting_setmode_msg_btn); } else { mbtnrcd.setvisibility(view.visible); mbottom.setvisibility(view.gone); chatting_mode_btn .setimageresource(r.drawable.chatting_setmode_voice_btn); btn_vocie = true; } } }); mbtnrcd.setontouchlistener(new ontouchlistener() { public boolean ontouch(view v, motionevent event) { //按下语音录制按钮时返回false执行父类ontouch return false; } }); } private string[] msgarray = new string[] { "有人就有恩怨","有恩怨就有江湖","人就是江湖","你怎么退出? ","生命中充满了巧合","两条平行线也会有相交的一天。"}; private string[] dataarray = new string[] { "2012-10-31 18:00", "2012-10-31 18:10", "2012-10-31 18:11", "2012-10-31 18:20", "2012-10-31 18:30", "2012-10-31 18:35"}; private final static int count = 6; public void initdata() { for (int i = 0; i < count; i++) { chatmsgentity entity = new chatmsgentity(); entity.setdate(dataarray[i]); if (i % 2 == 0) { entity.setname("白富美"); entity.setmsgtype(true); } else { entity.setname("高富帅"); entity.setmsgtype(false); } entity.settext(msgarray[i]); mdataarrays.add(entity); } madapter = new chatmsgviewadapter(this, mdataarrays); mlistview.setadapter(madapter); } public void onclick(view v) { // todo auto-generated method stub switch (v.getid()) { case r.id.btn_send: send(); break; case r.id.btn_back: finish(); break; } } private void send() { string contstring = medittextcontent.gettext().tostring(); if (contstring.length() > 0) { chatmsgentity entity = new chatmsgentity(); entity.setdate(getdate()); entity.setname("高富帅"); entity.setmsgtype(false); entity.settext(contstring); mdataarrays.add(entity); madapter.notifydatasetchanged(); medittextcontent.settext(""); mlistview.setselection(mlistview.getcount() - 1); } } private string getdate() { calendar c = calendar.getinstance(); string year = string.valueof(c.get(calendar.year)); string month = string.valueof(c.get(calendar.month)); string day = string.valueof(c.get(calendar.day_of_month) + 1); string hour = string.valueof(c.get(calendar.hour_of_day)); string mins = string.valueof(c.get(calendar.minute)); stringbuffer sbbuffer = new stringbuffer(); sbbuffer.append(year + "-" + month + "-" + day + " " + hour + ":" + mins); return sbbuffer.tostring(); } //按下语音录制按钮时 @override public boolean ontouchevent(motionevent event) { if (!environment.getexternalstoragedirectory().exists()) { toast.maketext(this, "no sdcard", toast.length_long).show(); return false; } if (btn_vocie) { system.out.println("1"); int[] location = new int[2]; mbtnrcd.getlocationinwindow(location); // 获取在当前窗口内的绝对坐标 int btn_rc_y = location[1]; int btn_rc_x = location[0]; int[] del_location = new int[2]; del_re.getlocationinwindow(del_location); int del_y = del_location[1]; int del_x = del_location[0]; if (event.getaction() == motionevent.action_down && flag == 1) { if (!environment.getexternalstoragedirectory().exists()) { toast.maketext(this, "no sdcard", toast.length_long).show(); return false; } system.out.println("2"); if (event.gety() > btn_rc_y && event.getx() > btn_rc_x) {//判断手势按下的位置是否是语音录制按钮的范围内 system.out.println("3"); mbtnrcd.setbackgroundresource(r.drawable.voice_rcd_btn_pressed); rcchat_popup.setvisibility(view.visible); voice_rcd_hint_loading.setvisibility(view.visible); voice_rcd_hint_rcding.setvisibility(view.gone); voice_rcd_hint_tooshort.setvisibility(view.gone); mhandler.postdelayed(new runnable() { public void run() { if (!isshosrt) { voice_rcd_hint_loading.setvisibility(view.gone); voice_rcd_hint_rcding .setvisibility(view.visible); } } }, 300); img1.setvisibility(view.visible); del_re.setvisibility(view.gone); startvoicet = systemclock.currentthreadtimemillis(); voicename = startvoicet + ".amr"; start(voicename); flag = 2; } } else if (event.getaction() == motionevent.action_up && flag == 2) {//松开手势时执行录制完成 system.out.println("4"); mbtnrcd.setbackgroundresource(r.drawable.voice_rcd_btn_nor); if (event.gety() >= del_y && event.gety() <= del_y + del_re.getheight() && event.getx() >= del_x && event.getx() <= del_x + del_re.getwidth()) { rcchat_popup.setvisibility(view.gone); img1.setvisibility(view.visible); del_re.setvisibility(view.gone); stop(); flag = 1; file file = new file(android.os.environment.getexternalstoragedirectory()+"/" + voicename); if (file.exists()) { file.delete(); } } else { voice_rcd_hint_rcding.setvisibility(view.gone); stop(); endvoicet = systemclock.currentthreadtimemillis(); flag = 1; int time = (int) ((endvoicet - startvoicet) / 1000); if (time < 1) { isshosrt = true; voice_rcd_hint_loading.setvisibility(view.gone); voice_rcd_hint_rcding.setvisibility(view.gone); voice_rcd_hint_tooshort.setvisibility(view.visible); mhandler.postdelayed(new runnable() { public void run() { voice_rcd_hint_tooshort .setvisibility(view.gone); rcchat_popup.setvisibility(view.gone); isshosrt = false; } }, 500); return false; } chatmsgentity entity = new chatmsgentity(); entity.setdate(getdate()); entity.setname("高富帅"); entity.setmsgtype(false); entity.settime(time+"\""); entity.settext(voicename); mdataarrays.add(entity); madapter.notifydatasetchanged(); mlistview.setselection(mlistview.getcount() - 1); rcchat_popup.setvisibility(view.gone); } } if (event.gety() < btn_rc_y) {//手势按下的位置不在语音录制按钮的范围内 system.out.println("5"); animation mlitteanimation = animationutils.loadanimation(this, r.anim.cancel_rc); animation mbiganimation = animationutils.loadanimation(this, r.anim.cancel_rc2); img1.setvisibility(view.gone); del_re.setvisibility(view.visible); del_re.setbackgroundresource(r.drawable.voice_rcd_cancel_bg); if (event.gety() >= del_y && event.gety() <= del_y + del_re.getheight() && event.getx() >= del_x && event.getx() <= del_x + del_re.getwidth()) { del_re.setbackgroundresource(r.drawable.voice_rcd_cancel_bg_focused); sc_img1.startanimation(mlitteanimation); sc_img1.startanimation(mbiganimation); } } else { img1.setvisibility(view.visible); del_re.setvisibility(view.gone); del_re.setbackgroundresource(0); } } return super.ontouchevent(event); } private static final int poll_interval = 300; private runnable msleeptask = new runnable() { public void run() { stop(); } }; private runnable mpolltask = new runnable() { public void run() { double amp = msensor.getamplitude(); updatedisplay(amp); mhandler.postdelayed(mpolltask, poll_interval); } }; private void start(string name) { msensor.start(name); mhandler.postdelayed(mpolltask, poll_interval); } private void stop() { mhandler.removecallbacks(msleeptask); mhandler.removecallbacks(mpolltask); msensor.stop(); volume.setimageresource(r.drawable.amp1); } private void updatedisplay(double signalema) { switch ((int) signalema) { case 0: case 1: volume.setimageresource(r.drawable.amp1); break; case 2: case 3: volume.setimageresource(r.drawable.amp2); break; case 4: case 5: volume.setimageresource(r.drawable.amp3); break; case 6: case 7: volume.setimageresource(r.drawable.amp4); break; case 8: case 9: volume.setimageresource(r.drawable.amp5); break; case 10: case 11: volume.setimageresource(r.drawable.amp6); break; default: volume.setimageresource(r.drawable.amp7); break; } } public void head_xiaohei(view v) { // 标题栏 返回按钮 } }
第四:自定义的显示适配器:
package com.example.voice_rcd; import java.util.list; import android.content.context; import android.media.mediaplayer; import android.media.mediaplayer.oncompletionlistener; import android.view.layoutinflater; import android.view.view; import android.view.view.onclicklistener; import android.view.viewgroup; import android.widget.baseadapter; import android.widget.textview; public class chatmsgviewadapter extends baseadapter { public static interface imsgviewtype { int imvt_com_msg = 0; int imvt_to_msg = 1; } private static final string tag = chatmsgviewadapter.class.getsimplename(); private list<chatmsgentity> coll; private context ctx; private layoutinflater minflater; private mediaplayer mmediaplayer = new mediaplayer(); public chatmsgviewadapter(context context, list<chatmsgentity> coll) { ctx = context; this.coll = coll; minflater = layoutinflater.from(context); } public int getcount() { return coll.size(); } public object getitem(int position) { return coll.get(position); } public long getitemid(int position) { return position; } public int getitemviewtype(int position) { // todo auto-generated method stub chatmsgentity entity = coll.get(position); if (entity.getmsgtype()) { return imsgviewtype.imvt_com_msg; } else { return imsgviewtype.imvt_to_msg; } } public int getviewtypecount() { // todo auto-generated method stub return 2; } public view getview(int position, view convertview, viewgroup parent) { final chatmsgentity entity = coll.get(position); boolean iscommsg = entity.getmsgtype(); viewholder viewholder = null; if (convertview == null) { if (iscommsg) { convertview = minflater.inflate( r.layout.chatting_item_msg_text_left, null); } else { convertview = minflater.inflate( r.layout.chatting_item_msg_text_right, null); } viewholder = new viewholder(); viewholder.tvsendtime = (textview) convertview .findviewbyid(r.id.tv_sendtime); viewholder.tvusername = (textview) convertview .findviewbyid(r.id.tv_username); viewholder.tvcontent = (textview) convertview .findviewbyid(r.id.tv_chatcontent); viewholder.tvtime = (textview) convertview .findviewbyid(r.id.tv_time); viewholder.iscommsg = iscommsg; convertview.settag(viewholder); } else { viewholder = (viewholder) convertview.gettag(); } viewholder.tvsendtime.settext(entity.getdate()); if (entity.gettext().contains(".amr")) { viewholder.tvcontent.settext(""); viewholder.tvcontent.setcompounddrawableswithintrinsicbounds(0, 0, r.drawable.chatto_voice_playing, 0); viewholder.tvtime.settext(entity.gettime()); } else { viewholder.tvcontent.settext(entity.gettext()); viewholder.tvcontent.setcompounddrawableswithintrinsicbounds(0, 0, 0, 0); viewholder.tvtime.settext(""); } viewholder.tvcontent.setonclicklistener(new onclicklistener() { public void onclick(view v) { if (entity.gettext().contains(".amr")) { playmusic(android.os.environment.getexternalstoragedirectory()+"/"+entity.gettext()) ; } } }); viewholder.tvusername.settext(entity.getname()); return convertview; } static class viewholder { public textview tvsendtime; public textview tvusername; public textview tvcontent; public textview tvtime; public boolean iscommsg = true; } /** * @description * @param name */ private void playmusic(string name) { try { if (mmediaplayer.isplaying()) { mmediaplayer.stop(); } mmediaplayer.reset(); mmediaplayer.setdatasource(name); mmediaplayer.prepare(); mmediaplayer.start(); mmediaplayer.setoncompletionlistener(new oncompletionlistener() { public void oncompletion(mediaplayer mp) { } }); } catch (exception e) { e.printstacktrace(); } } private void stop() { } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。