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

  1. 云栖社区>
  2. 博客列表>
  3. 正文

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

一叶飘舟 2014-09-06 16:15:00 浏览971 评论1

摘要: http://blog.csdn.net/junhuahouse/article/details/39076821 我们大家可能都看到过在自己使用社交Android软件的时候,会发现聊天页面的效果;有人说是气泡效果,也很像,是吧?那我们该怎么去实现那种效果呢?? 点击这里进入她的姊妹篇 点击这...

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

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

点击这里进入她的姊妹篇

点击这里下载源码

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

  1. public class MainActivity extends Activity {  
  2.   
  3.     private LinkedList<PeopleStudentBean> sList = null;  
  4.     private LinkedList<PeopleTeacherBean> tList = null;  
  5.     private LinkedList<Bean> 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<PeopleStudentBean>();  
  21.         tList = new LinkedList<PeopleTeacherBean>();  
  22.         beans = new LinkedList<Bean>();  
  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<PeopleStudentBean> sList = null;
	private LinkedList<PeopleTeacherBean> tList = null;
	private LinkedList<Bean> 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<PeopleStudentBean>();
		tList = new LinkedList<PeopleTeacherBean>();
		beans = new LinkedList<Bean>();
		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<Bean> 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<Bean> 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<Bean> beans = null;
	private LayoutInflater li;
	private final int ITEM_TYPES = 2, TYPE_0 = 0, TYPE_1 = 1;

	public CustomAdapter(Context context, LinkedList<Bean> 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参数,表示选项中显示的文字。




 

【云栖快讯】你想见的Java技术专家都在这了,向大佬提问,有问题必答  详情请点击

网友评论

1F
xiaoyan2015

web版仿微信聊天案例,使用HTML5+css3+weui+zepto等技术开发,有人物头像、、聊天气泡、聊天的当时时间、聊天内容、发送信-表情、微信红包-打赏-霸屏弹窗功能,还能长按提示功能~~~
https://yq.aliyun.com/articles/114660?spm=5176.8091938.0.0.iqNkTH

_4

006360_20170701135250829

007360_20170628172154239

一叶飘舟
文章1938篇 | 关注24
关注
先知(安全情报)平台提供私密的安全众测服务,可帮助企业全面发现业务漏洞及风险,按效果付费。 查看详情
用于实时预测用户对物品偏好,支持企业定制推荐算法,支持A/B Test效果对比 查看详情
大数据开发套件(Data IDE),提供可视化开发界面、离线任务调度运维、快速数据集成、多人... 查看详情
为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效... 查看详情
阿里云总监课正式启航

阿里云总监课正式启航