android 仿微信demo——微信消息界面實(shí)現(xiàn)(移動(dòng)端)
移動(dòng)端微信消息頁實(shí)現(xiàn)
在上一篇中主界面實(shí)現(xiàn)說過微信四個(gè)頁面中間都是是fragment的,并且四個(gè)fragment的布局都還沒實(shí)現(xiàn),所以這一篇主要實(shí)現(xiàn)微信消息界面的實(shí)現(xiàn)(第一個(gè)fragment)
微信消息頁是可以上下滑動(dòng),每一個(gè)列表最多都有可顯示五個(gè)數(shù)據(jù),還可以點(diǎn)擊列表
要實(shí)現(xiàn)上訴功能只需要在fragment布局中使用ListView,然后給ListView指定一個(gè)Item布局即可
修改微信消息界面fragment布局
weixin_fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="@drawable/main_list_divider_line" android:dividerHeight="1.5px" android:layout_marginBottom="50dp"> </ListView> </LinearLayout>
上述代碼自定義了一個(gè)分割線
微信消息頁每一個(gè)列表都有分割線,而系統(tǒng)自帶的分割線是充滿屏幕寬度的,所以要自己定義一個(gè)分割線
自定義分割線main_list_divider_line.xml
main_list_divider_line.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:left="80dp" android:right="0dp"> <shape android:shape="rectangle" > <solid android:color="#33000000" /> </shape> </item> </layer-list>
創(chuàng)建微信消息界面fragment中ListView對(duì)應(yīng)的item布局
weixin_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="80dp" android:layout_marginTop="300dp" android:padding="10dp" android:orientation="horizontal"> <ImageView android:id="@+id/img1" android:layout_width="20dp" android:layout_height="wrap_content" android:layout_weight="0.5"/> <LinearLayout android:orientation="vertical" android:layout_marginLeft="23dp" android:layout_width="8dp" android:layout_height="match_parent" android:layout_weight="4"> <TextView android:id="@+id/title" android:textColor="#000000" android:textSize="18dp" android:gravity="center_vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="2.5"/> <TextView android:id="@+id/content" android:textColor="#A8A8A8" android:gravity="center_vertical" android:singleLine="true" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1.5"/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingRight="-50dp" android:layout_weight="1" android:gravity="right" android:orientation="vertical"> <TextView android:id="@+id/time" android:textColor="#A8A8A8" android:textSize="15dp" android:layout_gravity="right" android:layout_marginRight="1dp" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.5"/> <ImageView android:id="@+id/code" android:background="@color/white" android:layout_gravity="right" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="0.5"/> </LinearLayout> </LinearLayout>
修改微信消息界面fragment.java代碼
package com.example.wxchatdemo; import android.annotation.SuppressLint; import android.app.Fragment; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.annotation.Nullable; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import com.example.wxchatdemo.adapter.ImageAdapter; import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @SuppressLint("ValidFragment") public class WeixinFragment extends Fragment { //微信號(hào),用于查找微信消息列表 private String number; // 聲明組件 private ListView listView; // 創(chuàng)建集合用于存儲(chǔ)服務(wù)器發(fā)來的顯示微信消息列表的一些信息 private List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); //自定義的一個(gè)Hander消息機(jī)制 private MyHander myhander = new MyHander(); /*有參構(gòu)造方法,參數(shù)為微信號(hào)*/ @SuppressLint("ValidFragment") WeixinFragment(String number) { this.number = number; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // 開一個(gè)線程完成網(wǎng)絡(luò)請(qǐng)求操作 Thread thread1 = new Thread(new Runnable() { @Override public void run() { httpUrlConnPost(String.valueOf(number)); } }); thread1.start(); /*等待網(wǎng)絡(luò)請(qǐng)求線程完成*/ try { thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } //獲取fragment布局 View view = inflater.inflate(R.layout.weixin_fragment, container, false); //初始化組件 listView = view.findViewById(R.id.listView); //創(chuàng)建自定義的適配器,用于把數(shù)據(jù)顯示在組件上 BaseAdapter adapter = new ImageAdapter(getActivity().getApplicationContext(), list); //設(shè)置適配器 listView.setAdapter(adapter); return view; } // 1.編寫一個(gè)發(fā)送請(qǐng)求的方法 // 發(fā)送請(qǐng)求的主要方法 public void httpUrlConnPost(String number) { HttpURLConnection urlConnection = null; URL url; try { // 請(qǐng)求的URL地地址 url = new URL( "http://100.2.178.10:8080/AndroidServer_war_exploded/WeixinInformation"); urlConnection = (HttpURLConnection) url.openConnection();// 打開http連接 urlConnection.setConnectTimeout(3000);// 連接的超時(shí)時(shí)間 urlConnection.setUseCaches(false);// 不使用緩存 // urlConnection.setFollowRedirects(false);是static函數(shù),作用于所有的URLConnection對(duì)象。 urlConnection.setInstanceFollowRedirects(true);// 是成員函數(shù),僅作用于當(dāng)前函數(shù),設(shè)置這個(gè)連接是否可以被重定向 urlConnection.setReadTimeout(3000);// 響應(yīng)的超時(shí)時(shí)間 urlConnection.setDoInput(true);// 設(shè)置這個(gè)連接是否可以寫入數(shù)據(jù) urlConnection.setDoOutput(true);// 設(shè)置這個(gè)連接是否可以輸出數(shù)據(jù) urlConnection.setRequestMethod("POST");// 設(shè)置請(qǐng)求的方式 urlConnection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");// 設(shè)置消息的類型 urlConnection.connect();// 連接,從上述至此的配置必須要在connect之前完成,實(shí)際上它只是建立了一個(gè)與服務(wù)器的TCP連接 JSONObject json = new JSONObject();// 創(chuàng)建json對(duì)象 //json.put("title", URLEncoder.encode(title, "UTF-8"));// 使用URLEncoder.encode對(duì)特殊和不可見字符進(jìn)行編碼 json.put("number", URLEncoder.encode(number, "UTF-8"));// 把數(shù)據(jù)put進(jìn)json對(duì)象中 String jsonstr = json.toString();// 把JSON對(duì)象按JSON的編碼格式轉(zhuǎn)換為字符串 // ------------字符流寫入數(shù)據(jù)------------ OutputStream out = urlConnection.getOutputStream();// 輸出流,用來發(fā)送請(qǐng)求,http請(qǐng)求實(shí)際上直到這個(gè)函數(shù)里面才正式發(fā)送出去 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));// 創(chuàng)建字符流對(duì)象并用高效緩沖流包裝它,便獲得最高的效率,發(fā)送的是字符串推薦用字符流,其它數(shù)據(jù)就用字節(jié)流 bw.write(jsonstr);// 把json字符串寫入緩沖區(qū)中 bw.flush();// 刷新緩沖區(qū),把數(shù)據(jù)發(fā)送出去,這步很重要 out.close(); bw.close();// 使用完關(guān)閉 Log.i("aa", urlConnection.getResponseCode() + ""); //以下判斷是否訪問成功,如果返回的狀態(tài)碼是200則說明訪問成功 if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {// 得到服務(wù)端的返回碼是否連接成功 // ------------字符流讀取服務(wù)端返回的數(shù)據(jù)------------ InputStream in = urlConnection.getInputStream(); BufferedReader br = new BufferedReader( new InputStreamReader(in)); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = br.readLine()) != null) {// BufferedReader特有功能,一次讀取一行數(shù)據(jù) System.out.println("測(cè)試:" + str); buffer.append(str); } in.close(); br.close(); JSONObject rjson = new JSONObject(buffer.toString()); String str1 = rjson.getJSONObject("json").get("titleimg").toString(); String[] pic = str1.split("\r\n"); String str2 = rjson.getJSONObject("json").get("title").toString(); String[] title = str2.split("\r\n"); String str3 = rjson.getJSONObject("json").get("content").toString(); String[] content = str3.split("\r\n"); String str4 = rjson.getJSONObject("json").get("time").toString(); String[] time = str4.split("\r\n"); String str5 = rjson.getJSONObject("json").get("showcode").toString(); String[] pic2 = str5.split("\r\n"); for (int i = 0; i < pic.length; i++) { Map<String, Object> map = new HashMap<String, Object>(); map.put("pic", pic[i]); System.out.println("網(wǎng)址:" + pic[i]); map.put("title", title[i]); System.out.println("網(wǎng)址:" + title[i]); map.put("content", content[i]); map.put("time", time[i]); map.put("code", pic2[i]); list.add(map);//將map放到list集合中 } boolean result = rjson.getBoolean("json");// 從rjson對(duì)象中得到key值為"json"的數(shù)據(jù),這里服務(wù)端返回的是一個(gè)boolean類型的數(shù)據(jù) System.out.println("json:===" + result); //如果服務(wù)器端返回的是true,則說明跳轉(zhuǎn)微信頁成功,跳轉(zhuǎn)微信頁失敗 if (result) {// 判斷結(jié)果是否正確 //在Android中http請(qǐng)求,必須放到線程中去作請(qǐng)求,但是在線程中不可以直接修改UI,只能通過hander機(jī)制來完成對(duì)UI的操作 myhander.sendEmptyMessage(1); Log.i("用戶:", "跳轉(zhuǎn)微信頁成功"); } else { myhander.sendEmptyMessage(2); System.out.println("222222222222222"); Log.i("用戶:", "跳轉(zhuǎn)微信頁失敗"); } } else { myhander.sendEmptyMessage(2); } } catch (Exception e) { e.printStackTrace(); Log.i("aa", e.toString()); System.out.println("11111111111111111"); myhander.sendEmptyMessage(2); } finally { urlConnection.disconnect();// 使用完關(guān)閉TCP連接,釋放資源 } } // 在Android中不可以在線程中直接修改UI,只能借助Handler機(jī)制來完成對(duì)UI的操作 class MyHander extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); //判斷hander的內(nèi)容是什么,如果是1則說明跳轉(zhuǎn)微信頁成功,如果是2說明跳轉(zhuǎn)微信頁失敗 switch (msg.what) { case 1: Log.i("aa", msg.what + ""); break; case 2: Log.i("aa", msg.what + ""); } } } }
上述代碼具體的內(nèi)容就不闡述了,代碼都有注釋。主要說一下上面給ListView設(shè)置適配器,它是自定義的適配器,通過繼承系統(tǒng)自帶適配器BaseAdapter,重寫相應(yīng)方法,把數(shù)據(jù)顯示在LlistView對(duì)應(yīng)的item布局相應(yīng)組件上,至于為什么要自定義,因?yàn)槲⑿畔㈨撁恳粋€(gè)列表都有至少兩個(gè)圖片數(shù)據(jù),而要把圖片加載到組件上需要用到工具類(后面會(huì)給出)
上面fragment.java代碼自定義了一個(gè)適配器,現(xiàn)在就來創(chuàng)建它,創(chuàng)建之前,可以先創(chuàng)建包單獨(dú)存放適配器,方便管理;
ImageAdapter.java
package com.example.wxchatdemo.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.example.wxchatdemo.tools.GetImageByUrl; import com.example.wxchatdemo.R; import java.util.List; import java.util.Map; public class ImageAdapter extends BaseAdapter { // 要顯示的數(shù)據(jù)的集合 private List<Map<String, Object>> data; // 接受上下文 private Context context; // 聲明內(nèi)部類對(duì)象 private ViewHolder viewHolder; public ImageAdapter(Context context, List<Map<String, Object>> data) { this.context = context; this.data = data; } // 返回的總個(gè)數(shù) @Override public int getCount() { // TODO Auto-generated method stub return data.size(); } // 返回每個(gè)條目對(duì)應(yīng)的數(shù)據(jù) @Override public Object getItem(int position) { // TODO Auto-generated method stub return data.get(position); } // 返回的id @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } // 返回這個(gè)條目對(duì)應(yīng)的控件對(duì)象 @Override public View getView(int position, View convertView, ViewGroup parent) { // 判斷當(dāng)前條目是否為null if (convertView == null) { viewHolder = new ViewHolder(); convertView = View.inflate(context, R.layout.weixin_item, null); viewHolder.img1 = (ImageView) convertView .findViewById(R.id.img1); viewHolder.title = (TextView) convertView .findViewById(R.id.title); viewHolder.content = (TextView) convertView .findViewById(R.id.content); viewHolder.time = (TextView) convertView .findViewById(R.id.time); viewHolder.code = (ImageView) convertView .findViewById(R.id.code); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } // 獲取List集合中的map對(duì)象 Map<String, Object> map = data.get(position); // 獲取圖片的url路徑 String pic = map.get("pic").toString(); // 這里調(diào)用了圖片加載工具類的setImage方法將圖片直接顯示到控件上 GetImageByUrl getImageByUrl = new GetImageByUrl(); getImageByUrl.setImage(viewHolder.img1, pic); String title = map.get("title").toString(); viewHolder.title.setText(title); String content = map.get("content").toString(); viewHolder.content.setText(content); String time = map.get("time").toString(); viewHolder.time.setText(time); // 獲取圖片的url路徑 String code = map.get("code").toString(); // 這里調(diào)用了圖片加載工具類的setImage方法將圖片直接顯示到控件上 GetImageByUrl getImageByUrl2 = new GetImageByUrl(); getImageByUrl2.setImage(viewHolder.code, code); return convertView; } /** * 內(nèi)部類 記錄單個(gè)條目中所有屬性 * * * */ class ViewHolder { public ImageView img1; public TextView title; public TextView content; public TextView time; public ImageView code; } }
上面用到圖片加載工具類,后面會(huì)給出
在工具包tools中創(chuàng)建圖片加載工具類GetImageByUrl.java
GetImageByUrl.java
package com.example.wxchatdemo.tools; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; import android.widget.ImageView; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; /** * 根據(jù)圖片url路徑獲取圖片 * * * */ public class GetImageByUrl { private PicHandler pic_hdl; private ImageView imgView; private String url; /** * 通過圖片url路徑獲取圖片并顯示到對(duì)應(yīng)控件上 * * * */ public void setImage(ImageView imgView, String url) { this.url = url; this.imgView = imgView; pic_hdl = new PicHandler(); Thread t = new LoadPicThread(); t.start(); } class LoadPicThread extends Thread { @Override public void run() { Bitmap img = getUrlImage(url); System.out.println(img + "---"); Message msg = pic_hdl.obtainMessage(); msg.what = 0; msg.obj = img; pic_hdl.sendMessage(msg); } } class PicHandler extends Handler { @Override public void handleMessage(Message msg) { Bitmap myimg = (Bitmap) msg.obj; imgView.setImageBitmap(myimg); } } public Bitmap getUrlImage(String url) { Bitmap img = null; try { URL picurl = new URL(url); HttpURLConnection conn = (HttpURLConnection) picurl .openConnection(); conn.setConnectTimeout(6000); conn.setDoInput(true); conn.setUseCaches(false); conn.connect(); InputStream is = conn.getInputStream(); img = BitmapFactory.decodeStream(is); is.close(); } catch (Exception e) { e.printStackTrace(); } return img; } }
總結(jié)
到此微信消息頁移動(dòng)端就完成了,由于服務(wù)端功能還沒實(shí)現(xiàn),所以測(cè)試時(shí)微信消息頁顯示的是空白的,因?yàn)長(zhǎng)istView對(duì)應(yīng)Item布局默認(rèn)是沒有數(shù)據(jù)的,數(shù)據(jù)是從服務(wù)器獲取的,下一篇會(huì)完善服務(wù)端功能,也希望大家可以關(guān)注腳本之家其他內(nèi)容!
相關(guān)文章
Android中Image的簡(jiǎn)單實(shí)例詳解
這篇文章主要為大家詳細(xì)介紹了Android中Image的簡(jiǎn)單實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12studio碰到問題:java.lang.UnsatisfiedLinkError解決辦法
這篇文章主要介紹了studio碰到問題:java.lang.UnsatisfiedLinkError解決辦法的相關(guān)資料,需要的朋友可以參考下2017-02-02android 自定義ScrollView實(shí)現(xiàn)背景圖片伸縮的實(shí)現(xiàn)代碼及思路
本文純屬個(gè)人見解,是對(duì)前面學(xué)習(xí)的總結(jié),如有描述不正確的地方還請(qǐng)高手指正~,首先還是按照通例給大家看下示例.2013-05-05Android使用OKHttp庫實(shí)現(xiàn)視頻文件的上傳到服務(wù)器功能
這篇文章主要介紹了Android使用OKHttp庫實(shí)現(xiàn)視頻文件的上傳到服務(wù)器功能,需要的朋友可以參考下2018-03-03Android編程之PopupWindow隱藏及顯示方法示例(showAtLocation,showAsDropDown
這篇文章主要介紹了Android編程之PopupWindow隱藏及顯示方法,結(jié)合實(shí)例形式分析了showAtLocation及showAsDropDown方法實(shí)現(xiàn)PopupWindow控件隱藏及顯示功能相關(guān)操作技巧,需要的朋友可以參考下2017-02-02Android Studio 3.1.3升級(jí)至3.6.1后舊項(xiàng)目的兼容操作方法
這篇文章主要介紹了Android Studio 3.1.3升級(jí)至3.6.1后舊項(xiàng)目的兼容操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03OpenGL ES 矩陣變換及其數(shù)學(xué)原理詳解(五)
這篇文章主要為大家詳細(xì)介紹了OpenGL ES 矩陣變換及其數(shù)學(xué)原理的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Android Studio打包.so庫到apk中實(shí)例詳解
這篇文章主要介紹了Android Studio打包.so庫到apk中實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04