在openfire服务器下制作的仿微信会话界面,包括接收用户的消息,初始化数据列表ListView,好友名称,好友头像,聊天消息,消息发送时间等,以及统计好友消息数目。
界面效果:
由于会话界面用到的是Fragment,于是想要实现自定义ListView利用到了ListFragment组件,直接让当前Fragment继承ListFragment类;然后就是Fragment的布局文件和item布局文件,将item整理成理想的样式;在Fragment中获取用户收到的好友消息,好友名,头像等,使用SimpleAdapter适配器进行数据适配;统计好友发送的消息数目,显示在UI上,已经点击item项触发事件,跳转聊天页面。
1、Fragment的布局文件fragment_one.xml,这里就仅仅是一个ListView,要注意的是ListView的id必须是Android:list,此为ListFragment指定的ListView项。
<?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="match_parent" android:orientation="vertical" > <ListView android:id="@+id/android:list" android:layout_width="fill_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout>
2、Fragment的item项布局文件fragment_one_item.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="wrap_content" android:paddingBottom="5dp" android:background="@drawable/linearlayout_boder"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:orientation="horizontal" > <ImageView android:id="@+id/tab1_item_img" android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="center_vertical" /> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="0.95" android:layout_marginLeft="5dp" android:orientation="vertical" android:layout_gravity="center_vertical" android:gravity="center_vertical"> <TextView android:id="@+id/tab1_item_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:textSize="18sp" android:textStyle="bold" /> <TextView android:id="@+id/tab1_item_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:textSize="12sp" android:text="12313131313" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" android:gravity="center_vertical" android:orientation="vertical" android:layout_marginTop="5dp" android:layout_marginRight="5dp" > <TextView android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="top" /> </LinearLayout> </LinearLayout> <TextView android:id="@+id/number" android:layout_width="20dp" android:layout_height="20dp" android:layout_marginLeft="45dp" android:gravity="center" android:textColor="#FFF" android:background="@drawable/number" /> </RelativeLayout>3、主界面TabFragment.java,包含获取所有好友发送的消息,使用SimpleAdapter进行ListView的数据适配,以及指定好友消息数目的统计,这里利用到两个list<Map<String,Object>>对象,其中list对象用于存储所有接收到的消息,统计指定好友消息数目;showlist显示在页面上的数据,将同一个好友发送的消息去重,仅显示最后收到的消息,并倒序显示在页面上。
package com.example.eric_jqm_chat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.ChatManager; import org.jivesoftware.smack.ChatManagerListener; import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.Roster; import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; import com.example.eric_jqm_chat.ChatActivity.ChatHandler; import com.example.eric_jqm_chat.TabFragment4.UserAndPassword; import android.R.color; import android.R.string; import android.app.Activity; import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.ListFragment; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.SimpleAdapter.ViewBinder; import android.widget.TextView; import android.widget.Toast; import android.widget.ArrayAdapter; public class TabFragment extends ListFragment{ private XMPPConnection con = ConnectServer.getInstance().getConnection(); private UserAndPasswordOne mUserAndPassword; private String name,password,friend,time; private List<Map<String,Object>> list = new ArrayList<Map<String,Object>>(); private List<Map<String,Object>> showlist = new ArrayList<Map<String,Object>>(); private SimpleAdapter adapter; private FragmentOneHandler handler; private String[] from = new String[] {"time","friend","chat","img","number"}; private int[] to = new int[] {R.id.time,R.id.tab1_item_name,R.id.tab1_item_text,R.id.tab1_item_img,R.id.number}; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_one, container, false); return v; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); name = mUserAndPassword.getUserOne(name); password = mUserAndPassword.getPasswordOne(password); //监听用户接收到的消息的副线程 Thread thread = new Thread(new Runnable(){ @Override public void run() { //接收用户发来的消息 try { con.getChatManager().addChatListener(new ChatManagerListener() { @Override public void chatCreated(Chat chat, boolean arg1) { chat.addMessageListener(new MessageListener() { @Override public void processMessage(Chat chat, Message msg) { friend = msg.getFrom(); friend = friend.substring(0, friend.indexOf("@")); android.os.Message m = new android.os.Message(); if(msg.getBody()!= null){ Bundle b= new Bundle(); b.putString("msg", msg.getBody()); b.putString("friend", friend); m.setData(b); handler.sendMessage(m); } } }); } }); while (true); } catch (Exception e) { System.out.println("try error"); e.printStackTrace(); } } }); thread.start(); handler = new FragmentOneHandler(); adapter = new SimpleAdapter(getActivity(), getSimpleData(), R.layout.fragment_one_item, from, to); adapter.notifyDataSetChanged();//刷新listview setListAdapter(adapter); //使SimpleAdapter加载Drawable类 adapter.setViewBinder(new ViewBinder() { @Override public boolean setViewValue(View view, Object data, String arg2) { if(view instanceof ImageView && data instanceof Drawable){ ImageView iv = (ImageView)view; iv.setImageDrawable((Drawable)data); return true; }else{ return false; } } }); } private List<Map<String,Object>> getSimpleData(){ return showlist; } //将数据添加到List的函数实现 public void addMessageToListview(String time,String friend,String chat){ HashMap<String,Object> map = new HashMap<String,Object>(); //遍历showlist去除同名的项 try { for(Map<String,Object> m : showlist){ if(m.get("friend").toString().equals(friend)){ showlist.remove(m); } } } catch (Exception e) { e.printStackTrace(); } //添加数据到list和showlist其中list为所有收到的消息,showlist页面显示用 map.put("time", time); map.put("friend", friend); map.put("chat", chat); map.put("img", new TabFragment2().getUserImage(con, friend)); if(countNumber().get(friend)==null){ map.put("number", 1); }else{ map.put("number", countNumber().get(friend)); } list.add(map); System.out.println("^^^^resultMap="+countNumber()); showlist.add(map); adapter.notifyDataSetChanged(); } //统计好友消息数目,返回Map为好友名:消息数目 public Map<String,Integer> countNumber(){ Map<String,Integer> resultMap =new HashMap<String, Integer>(); for(Map<String,Object> map: list){ for(String s: map.keySet()){ if(s.equals("friend")){ String friendName = map.get("friend").toString(); Integer count = resultMap.get(friendName); if(count!=null){ resultMap.put(friendName, count+1); }else{ resultMap.put(friendName, 2); } } } } return resultMap; } //列表点击事件 @Override public void onListItemClick(ListView l, View v, int position, long id) { //获取ListView点击位置item项的键名为friend的值,即好友名 Map<String,Object> m = getSimpleData().get(position); Iterator it = m.keySet().iterator(); Object o = m.get("friend"); String friend = o.toString(); //进行页面跳转,并传值给聊天页面ChatActivity,包括用户名密码,好友名 Intent intent = new Intent(); intent.setClass(getActivity(),ChatActivity.class); intent.putExtra("friend", friend); intent.putExtra("name", name); intent.putExtra("password", password); startActivity(intent); super.onListItemClick(l, v, position, id); } public interface UserAndPasswordOne { public String getUserOne(String user); public String getPasswordOne(String password); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mUserAndPassword = (UserAndPasswordOne) activity; } catch (Exception e) { e.printStackTrace(); System.out.println("接口实例化异常"); } } public class FragmentOneHandler extends Handler{ @Override public void handleMessage(android.os.Message msg) { super.handleMessage(msg); //获取接收的好友名及聊天消息 Bundle b = msg.getData(); String chatMsg = b.getString("msg"); String friend = b.getString("friend"); //获取当前时间 SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss"); Date curDate = new Date(System.currentTimeMillis()); time = formatter.format(curDate); //添加数据到list和showlist addMessageToListview(time, friend, chatMsg); //将showlist按时间排成倒序 Collections.sort(showlist, new Comparator<Map<String,Object>>() { public int compare(Map<String,Object> a, Map<String,Object> b) { String at = a.get("time").toString(); String bt = b.get("time").toString(); if (at.compareTo(bt)<0) { return 1; } else if (at.equals(bt)) { return 0; } else { return -1; } } }); } } }