仿微信、QQ聊天界面私信对话效果

简介:

http://blog.csdn.net/junhuahouse/article/details/39076821

我们大家可能都看到过在自己使用社交Android软件的时候,会发现聊天页面的效果;有人说是气泡效果,也很像,是吧?那我们该怎么去实现那种效果呢??

点击这里进入她的姊妹篇

点击这里下载源码

这个就是效果:有人物头像、聊天的当时时间、聊天内容、发送信息等;其实呢,她的思路很简单,我也弄了几个小时!恩,那我们就简单详细的聊聊吧!先看源代码:项目入口MainActivity.java:

  1. public class MainActivity extends Activity {  
  2.   
  3.     private LinkedList sList = null;  
  4.     private LinkedList tList = null;  
  5.     private LinkedList beans = null;  
  6.   
  7.   
  8.     /** 聊天message 格式 */  
  9.     private ListView listView;  
  10.     /** 信息编辑框 */  
  11.     private EditText edt;  
  12.     /** 信息发送按钮 */  
  13.     private Button btnEnter;  
  14.   
  15.     private CustomAdapter adapter;  
  16.   
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         sList = new LinkedList();  
  21.         tList = new LinkedList();  
  22.         beans = new LinkedList();  
  23.         String[] msg = new String[] { "你好!""你也在金象工作吗?""我在**扫大街呢,这里可舒服了!",  
  24.                 "原来你也细化这个工作啊,我这里还招人呢,你来不?来的话,我一句话的事儿!""呵呵,你好!""是的,你在哪里呢?",  
  25.                 "吼吼,这么便宜的事儿?!,我怎么没有遇到呢。""恩,好啊 好啊。那等着我。。。" };  
  26.   
  27.         // 0 是教师; 1 是学生   
  28.         for (int i = 0; i < 4; i++) {  
  29.             sList.add(new PeopleStudentBean(msg[i], R.drawable.you,""1));  
  30.             tList.add(new PeopleTeacherBean(msg[i + 4], R.drawable.me,""0));  
  31.         }  
  32.   
  33.         // 归放到 同一个 类集合Bean中   
  34.         for (int j = 0; j < sList.size(); j++) {  
  35.   
  36.             beans.add(sList.get(j));  
  37.             beans.add(tList.get(j));  
  38.         }  
  39.   
  40.         setContentView(R.layout.activity_main);  
  41.         initViewsMethod();  
  42.         onHandleMethod();  
  43.     }  
  44.       
  45.     /** 处理listView 的 item方法  */  
  46.     private void initViewsMethod(){  
  47.         listView = (ListView) findViewById(R.id.lvMessages);  
  48.         edt = (EditText) findViewById(R.id.edt);  
  49.         btnEnter = (Button) findViewById(R.id.enter);  
  50.   
  51.         listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {  
  52.               
  53.             @Override  
  54.             public void onCreateContextMenu(ContextMenu menu, View v,  
  55.                     ContextMenuInfo menuInfo) {  
  56.                 // TODO Auto-generated method stub   
  57.                   
  58.                 menu.setHeaderTitle("提示:");  
  59.                 menu.setHeaderIcon(android.R.drawable.stat_notify_error);  
  60.                 menu.add(001"删除");  
  61.                 menu.add(110"取消");  
  62.                   
  63.             }  
  64.         });  
  65.           
  66.     }  
  67.       
  68.       
  69.     /** 处理发送信息的方法  */  
  70.     public void onHandleMethod(){  
  71.         adapter = new CustomAdapter(this, beans);  
  72.         listView.setAdapter(adapter);  
  73.         btnEnter.setOnClickListener(new OnClickListener() {  
  74.               
  75.             @Override  
  76.             public void onClick(View v) {  
  77.                 // TODO Auto-generated method stub   
  78.                 String txt = edt.getText().toString();  
  79.                 if(null == txt)  
  80.                     Toast.makeText(getApplicationContext(), "发送内容不能为空 !", Toast.LENGTH_SHORT).show();  
  81.                 adapter.addItemNotifiChange(new Bean(txt, R.drawable.me, new Date()+""0));  
  82.                 edt.setText("");  
  83.                 listView.setSelection(beans.size()-1);  
  84.             }  
  85.         });  
  86.     }  
  87.   
  88.     @Override  
  89.     public boolean onContextItemSelected(MenuItem item) {  
  90.         // TODO Auto-generated method stub   
  91.         switch (item.getItemId()) {  
  92.         case 0:  
  93.             Toast.makeText(getApplicationContext(), "删除成功", Toast.LENGTH_SHORT).show();  
  94.             AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();  
  95.             Bean bean = (Bean) adapter.getItem(info.position);  
  96.             beans.remove(bean);  
  97.             adapter.notifyDataSetChanged();  
  98.             break;  
  99.         }  
  100.         return super.onContextItemSelected(item);  
  101.   
  102.     }  
public class MainActivity extends Activity {

	private LinkedList sList = null;
	private LinkedList tList = null;
	private LinkedList beans = null;


	/** 聊天message 格式 */
	private ListView listView;
	/** 信息编辑框 */
	private EditText edt;
	/** 信息发送按钮 */
	private Button btnEnter;

	private CustomAdapter adapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		sList = new LinkedList();
		tList = new LinkedList();
		beans = new LinkedList();
		String[] msg = new String[] { "你好!", "你也在金象工作吗?", "我在天安门扫大街呢,这里可舒服了!",
				"原来你也细化这个工作啊,我这里还招人呢,你来不?来的话,我一句话的事儿!", "呵呵,你好!", "是的,你在哪里呢?",
				"吼吼,这么便宜的事儿?!,我怎么没有遇到呢。", "恩,好啊 好啊。那等着我。。。" };

		// 0 是教师; 1 是学生
		for (int i = 0; i < 4; i++) {
			sList.add(new PeopleStudentBean(msg[i], R.drawable.you,"", 1));
			tList.add(new PeopleTeacherBean(msg[i + 4], R.drawable.me,"", 0));
		}

		// 归放到 同一个 类集合Bean中
		for (int j = 0; j < sList.size(); j++) {

			beans.add(sList.get(j));
			beans.add(tList.get(j));
		}

		setContentView(R.layout.activity_main);
		initViewsMethod();
		onHandleMethod();
	}
	
	/** 处理listView 的 item方法  */
	private void initViewsMethod(){
		listView = (ListView) findViewById(R.id.lvMessages);
		edt = (EditText) findViewById(R.id.edt);
		btnEnter = (Button) findViewById(R.id.enter);

		listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
			
			@Override
			public void onCreateContextMenu(ContextMenu menu, View v,
					ContextMenuInfo menuInfo) {
				// TODO Auto-generated method stub
				
				menu.setHeaderTitle("提示:");
				menu.setHeaderIcon(android.R.drawable.stat_notify_error);
				menu.add(0, 0, 1, "删除");
				menu.add(1, 1, 0, "取消");
				
			}
		});
		
	}
	
	
	/** 处理发送信息的方法  */
	public void onHandleMethod(){
		adapter = new CustomAdapter(this, beans);
		listView.setAdapter(adapter);
		btnEnter.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				String txt = edt.getText().toString();
				if(null == txt)
					Toast.makeText(getApplicationContext(), "发送内容不能为空 !", Toast.LENGTH_SHORT).show();
				adapter.addItemNotifiChange(new Bean(txt, R.drawable.me, new Date()+"", 0));
				edt.setText("");
		        listView.setSelection(beans.size()-1);
			}
		});
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		switch (item.getItemId()) {
		case 0:
			Toast.makeText(getApplicationContext(), "删除成功", Toast.LENGTH_SHORT).show();
			AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
			Bean bean = (Bean) adapter.getItem(info.position);
			beans.remove(bean);
			adapter.notifyDataSetChanged();
			break;
		}
		return super.onContextItemSelected(item);

	}

填充效果内容对应的自定义适配器CustomAdapter.java:

  1. public class CustomAdapter extends BaseAdapter {  
  2.   
  3.     private LinkedList beans = null;  
  4.     private LayoutInflater li;  
  5.     private final int ITEM_TYPES = 2, TYPE_0 = 0, TYPE_1 = 1;  
  6.   
  7.     public CustomAdapter(Context context, LinkedList beans) {  
  8.         // TODO Auto-generated constructor stub   
  9.         this.beans = beans;  
  10.         li = LayoutInflater.from(context);  
  11.   
  12.     }  
  13.   
  14.     @Override  
  15.     public int getCount() {  
  16.         // TODO Auto-generated method stub   
  17.         return beans.size();  
  18.     }  
  19.   
  20.     @Override  
  21.     public Object getItem(int position) {  
  22.         // TODO Auto-generated method stub   
  23.         return beans.get(position);  
  24.     }  
  25.   
  26.     @Override  
  27.     public long getItemId(int position) {  
  28.         // TODO Auto-generated method stub   
  29.         return position;  
  30.     }  
  31.   
  32.     @Override  
  33.     public int getViewTypeCount() {  
  34.         // TODO Auto-generated method stub   
  35.         return ITEM_TYPES;  
  36.     }  
  37.   
  38.     @Override  
  39.     public int getItemViewType(int position) {  
  40.         // TODO Auto-generated method stub   
  41.         int tp = beans.get(position).getId();  
  42.         if (TYPE_0 == tp)  
  43.             return TYPE_0;  
  44.         else if (TYPE_1 == tp)  
  45.             return TYPE_1;  
  46.         return TYPE_0;  
  47.     }  
  48.   
  49.     @Override  
  50.     public View getView(int position, View convertView, ViewGroup parent) {  
  51.         // TODO Auto-generated method stub   
  52.   
  53.         PeopleView s = null;  
  54.         Bean bean = beans.get(position);  
  55.         int type = getItemViewType(position);  
  56.   
  57.         if (null == convertView) {  
  58.             s = new PeopleView();  
  59.   
  60.             switch (type) {  
  61.             case TYPE_0:  
  62.                 convertView = li.inflate(R.layout.listview_item_teacher, null);  
  63.                 break;  
  64.             case TYPE_1:  
  65.                 convertView = li.inflate(R.layout.listview_item_student, null);  
  66.                 break;  
  67.             }  
  68.   
  69.             s.time = (TextView) convertView.findViewById(R.id.Time);  
  70.             s.message = (TextView) convertView.findViewById(R.id.Msg);  
  71.             s.portrait = (ImageView) convertView.findViewById(R.id.Img);  
  72.             convertView.setTag(s);  
  73.         } else  
  74.             s = (PeopleView) convertView.getTag();  
  75.         s.time.setText(DateFomats.getCurrentTime(new Date().getTime()));  
  76.         s.message.setText(bean.gettMessage());  
  77.         s.portrait.setImageResource(R.drawable.you);  
  78.   
  79.         return convertView;  
  80.   
  81.     }  
  82.   
  83.     class PeopleView {  
  84.         TextView time;  
  85.         TextView message;  
  86.         ImageView portrait;  
  87.     }  
  88.   
  89.     /** 添加发表私信内容,更新列表 */  
  90.     public void addItemNotifiChange(Bean bean) {  
  91.         beans.add(bean);  
  92.         notifyDataSetChanged();  
  93.   
  94.     }  
  95.   
  96. }  
public class CustomAdapter extends BaseAdapter {

	private LinkedList beans = null;
	private LayoutInflater li;
	private final int ITEM_TYPES = 2, TYPE_0 = 0, TYPE_1 = 1;

	public CustomAdapter(Context context, LinkedList beans) {
		// TODO Auto-generated constructor stub
		this.beans = beans;
		li = LayoutInflater.from(context);

	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return beans.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return beans.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public int getViewTypeCount() {
		// TODO Auto-generated method stub
		return ITEM_TYPES;
	}

	@Override
	public int getItemViewType(int position) {
		// TODO Auto-generated method stub
		int tp = beans.get(position).getId();
		if (TYPE_0 == tp)
			return TYPE_0;
		else if (TYPE_1 == tp)
			return TYPE_1;
		return TYPE_0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub

		PeopleView s = null;
		Bean bean = beans.get(position);
		int type = getItemViewType(position);

		if (null == convertView) {
			s = new PeopleView();

			switch (type) {
			case TYPE_0:
				convertView = li.inflate(R.layout.listview_item_teacher, null);
				break;
			case TYPE_1:
				convertView = li.inflate(R.layout.listview_item_student, null);
				break;
			}

			s.time = (TextView) convertView.findViewById(R.id.Time);
			s.message = (TextView) convertView.findViewById(R.id.Msg);
			s.portrait = (ImageView) convertView.findViewById(R.id.Img);
			convertView.setTag(s);
		} else
			s = (PeopleView) convertView.getTag();
		s.time.setText(DateFomats.getCurrentTime(new Date().getTime()));
		s.message.setText(bean.gettMessage());
		s.portrait.setImageResource(R.drawable.you);

		return convertView;

	}

	class PeopleView {
		TextView time;
		TextView message;
		ImageView portrait;
	}

	/** 添加发表私信内容,更新列表 */
	public void addItemNotifiChange(Bean bean) {
		beans.add(bean);
		notifyDataSetChanged();

	}

}


我想大家从代码中也已经看出端倪了;她的实现思路是使用ListView,在ListView中对其item布局展示做出变动。也就是说,这个Listview中item要用到两种布局,然后通过用户的   Id 进行判断 ,不同 id 对应不同的聊天布局。然后按照时间的顺序展示在界面上(当然这个是后台提供的,你不需要进行什么作为,这里只是自己添加排布的);为了实现的高效率,在创建item布局时候控件的两类布局的id使用同一套。这是关键的一点,这样的话在进行Layout布局初始化的时候可以使ListView得到优化。还要注意,要在适配器中重写方法:

  1. getViewTypeCount()  
getViewTypeCount()

和重写方法:

  1. getItemViewType(int position)  
 getItemViewType(int position)

上面第一个方法表返回值多少,对应的该ListView就会有有多少种的item布局类型,即在加载适配的时候每加载一次对话信息会走getView(int position ,View convertView ,ViewGroup parent);方法多少遍。如果按照原来的普通ListView适配器填充的话,现在的这个有两种item布局展示,为展示其对话效果在每走两次getView()方法 就相当于普通的ListView适配方法走一次,这样才能展示出我们想要的不同布局item的展示效果。第二个方法通过参数position对用户的id进行处理判断,并返回我们自定义布局类型或者说用户 id 所对应的类型数值值(这个是我们自己设置的),然后在getView()方法中通过方法获取不同布局类型对应的我们所设置的数值来进行判断此时我们应该展示那种itme布局,并来初始化该布局;

另外,ListView对应的item;如果想长按删除要实现其监听

  1. listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener()   
listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() 

和监听必须实现的方法;以及重写回调的方法,对被点击的item做出处理

  1. @Override  
  2. blic boolean onContextItemSelected(MenuItem item)  
  @Override
public boolean onContextItemSelected(MenuItem item)

顺便提一下:

  1. menu.add(001"删除");  
menu.add(0, 0, 1, "删除");

       第一个int类型的group ID参数,代表的是组概念,你可以将几个菜单项归为一组,以便更好的以组的方式管理你的菜单按钮。
       第二个int类型的item ID参数,代表的是项目编号。这个参数非常重要,一个item ID对应一个menu中的选项。在后面使用菜单的时候,就靠这个item ID来判断你使用的是哪个选项。
       第三个int类型的order ID参数,代表的是菜单项的显示顺序。默认是0,表示菜单的显示顺序就是按照add的显示顺序来显示。
       第四个String类型的title参数,表示选项中显示的文字。




 

相关文章
|
27天前
|
移动开发 监控 小程序
mPaaS常见问题之音视频通话微信小程序通话界面录制为画中画模式如何解决
mPaaS(移动平台即服务,Mobile Platform as a Service)是阿里巴巴集团提供的一套移动开发解决方案,它包含了一系列移动开发、测试、监控和运营的工具和服务。以下是mPaaS常见问题的汇总,旨在帮助开发者和企业用户解决在使用mPaaS产品过程中遇到的各种挑战
26 0
|
6月前
|
JSON 小程序 开发工具
微信小程序进阶——会议OA其他界面
微信小程序进阶——会议OA其他界面
41 0
|
9月前
|
搜索推荐 Python
将微信聊天做成滚动视频,聊天记录滚动播放
Python实现滚动聊天记录视频制作教程
|
存储 NoSQL 安全
取代微信?RocketChat开源聊天应用搭建教程
取代微信?RocketChat开源聊天应用搭建教程
取代微信?RocketChat开源聊天应用搭建教程
|
JavaScript 前端开发
uniapp仿微信聊天室|仿微信界面
基于uniapp+vue仿微信聊天室uniapp-chatroom项目,vue语法及类似小程序api开发原生APP应用,实现了发送图文消息、表情(gif动图),图片预览、地图位置、红包、仿微信朋友圈等功能。
2898 0
|
5月前
|
JSON 小程序 数据格式
微信小程序自定义组件及会议管理与个人中心界面搭建
微信小程序自定义组件及会议管理与个人中心界面搭建
45 0
|
6月前
|
JSON 小程序 JavaScript
微信小程序开发之会议OA的会议界面,投票界面
微信小程序开发之会议OA的会议界面,投票界面
34 0
|
6月前
|
JSON 小程序 开发工具
微信小程序进阶——会议OA其他界面
微信小程序进阶——会议OA其他界面
29 0
|
9月前
|
自然语言处理 Python
|
10月前
|
JSON 小程序 API
微信小程序设置表单界面
微信小程序设置表单界面
228 0

热门文章

最新文章