原理:Android平台上,典型的以腾讯的QQ、微信这些聊天消息界面通常可以采用ListView设计与实现,需要使用ListView 适配器Adapter的getItemViewType()和getViewTypeCount()。
在ListView的适配器中,每一次getView时候,首先要判断view的类型getItemViewType(),然后根据不同的类型加载不同的布局view。
至于底部发送消息的窗口,每次发送完消息,需要将ListView滚动到底部,以免输入键盘遮挡住数据而致使用户看不到刚刚发送的消息。
现在给出一个Android平台上简单的设计与实现方案。效果如图所示:

测试的主Activity MainActivity.java:

<span class="hljs-keyword">package</span> zhangphil.chat;<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.HashMap;<span class="hljs-keyword">import</span> android.app.Activity;
<span class="hljs-keyword">import</span> android.content.Context;
<span class="hljs-keyword">import</span> android.os.Bundle;
<span class="hljs-keyword">import</span> android.view.ContextMenu;
<span class="hljs-keyword">import</span> android.view.LayoutInflater;
<span class="hljs-keyword">import</span> android.view.View;
<span class="hljs-keyword">import</span> android.view.ViewGroup;
<span class="hljs-keyword">import</span> android.view.ContextMenu.ContextMenuInfo;
<span class="hljs-keyword">import</span> android.widget.ArrayAdapter;
<span class="hljs-keyword">import</span> android.widget.Button;
<span class="hljs-keyword">import</span> android.widget.EditText;
<span class="hljs-keyword">import</span> android.widget.ListView;
<span class="hljs-keyword">import</span> android.widget.TextView;<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Activity</span> </span>{<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> VIEW_TYPE = <span class="hljs-number">0xb01</span>;<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> VIEW_TYPE_LEFT = -<span class="hljs-number">10</span>;<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> VIEW_TYPE_RIGHT = -<span class="hljs-number">11</span>;<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> MESSAGE = <span class="hljs-number">0xb02</span>;<span class="hljs-keyword">private</span> ArrayList<HashMap<Integer, Object>> items = <span class="hljs-keyword">null</span>;<span class="hljs-annotation">@Override</span><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> </span>{<span class="hljs-keyword">super</span>.onCreate(savedInstanceState);setContentView(R.layout.activity_main);<span class="hljs-keyword">final</span> ListView listView = (ListView) findViewById(android.R.id.list);items = <span class="hljs-keyword">new</span> ArrayList<HashMap<Integer, Object>>();<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">8</span>; i++) {<span class="hljs-keyword">if</span> (i % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>) {HashMap<Integer, Object> map = <span class="hljs-keyword">new</span> HashMap<Integer, Object>();map.put(VIEW_TYPE, VIEW_TYPE_LEFT);map.put(MESSAGE, <span class="hljs-string">"对方说的消息"</span> + i);items.add(map);} <span class="hljs-keyword">else</span> {HashMap<Integer, Object> map = <span class="hljs-keyword">new</span> HashMap<Integer, Object>();map.put(VIEW_TYPE, VIEW_TYPE_RIGHT);map.put(MESSAGE, <span class="hljs-string">"我说的消息"</span> + i);items.add(map);}}<span class="hljs-keyword">final</span> MyAdapter adapter = <span class="hljs-keyword">new</span> MyAdapter(<span class="hljs-keyword">this</span>, -<span class="hljs-number">1</span>);listView.setAdapter(adapter);<span class="hljs-keyword">final</span> EditText msgEditText = (EditText) findViewById(R.id.msgEditText);Button button = (Button) findViewById(R.id.msgSend);button.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span><span class="hljs-params">(View v)</span> </span>{String msg = msgEditText.getText() + <span class="hljs-string">""</span>;HashMap<Integer, Object> map = <span class="hljs-keyword">new</span> HashMap<Integer, Object>();map.put(VIEW_TYPE, VIEW_TYPE_RIGHT);map.put(MESSAGE, msg);items.add(map);adapter.notifyDataSetChanged();<span class="hljs-comment">// 发送后清空输入框内容</span>msgEditText.setText(<span class="hljs-keyword">null</span>);<span class="hljs-comment">// 输入框发送消息后将ListView滚动到最底部</span>listView.setSelection(ListView.FOCUS_DOWN);}});}<span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAdapter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ArrayAdapter</span> </span>{<span class="hljs-keyword">private</span> LayoutInflater layoutInflater;<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MyAdapter</span><span class="hljs-params">(Context context, <span class="hljs-keyword">int</span> resource)</span> </span>{<span class="hljs-keyword">super</span>(context, resource);layoutInflater = LayoutInflater.from(context);}<span class="hljs-annotation">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> View <span class="hljs-title">getView</span><span class="hljs-params">(<span class="hljs-keyword">int</span> pos, View convertView, ViewGroup parent)</span> </span>{<span class="hljs-keyword">int</span> type = getItemViewType(pos);String msg = getItem(pos);<span class="hljs-keyword">switch</span> (type) {<span class="hljs-keyword">case</span> VIEW_TYPE_LEFT:convertView = layoutInflater.inflate(R.layout.left, <span class="hljs-keyword">null</span>);TextView textLeft = (TextView) convertView.findViewById(R.id.textView);textLeft.setText(msg);<span class="hljs-keyword">break</span>;<span class="hljs-keyword">case</span> VIEW_TYPE_RIGHT:convertView = layoutInflater.inflate(R.layout.right, <span class="hljs-keyword">null</span>);TextView textRight = (TextView) convertView.findViewById(R.id.textView);textRight.setText(msg);<span class="hljs-keyword">break</span>;}<span class="hljs-keyword">return</span> convertView;}<span class="hljs-annotation">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getItem</span><span class="hljs-params">(<span class="hljs-keyword">int</span> pos)</span> </span>{String s = items.get(pos).get(MESSAGE) + <span class="hljs-string">""</span>;<span class="hljs-keyword">return</span> s;}<span class="hljs-annotation">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCount</span><span class="hljs-params">()</span> </span>{<span class="hljs-keyword">return</span> items.size();}<span class="hljs-annotation">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getItemViewType</span><span class="hljs-params">(<span class="hljs-keyword">int</span> pos)</span> </span>{<span class="hljs-keyword">int</span> type = (Integer) items.get(pos).get(VIEW_TYPE);<span class="hljs-keyword">return</span> type;}<span class="hljs-annotation">@Override</span><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getViewTypeCount</span><span class="hljs-params">()</span> </span>{<span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;}}
}

MainActivity.java需要的布局文件activity_main.xml:

<span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag"><<span class="hljs-title">RelativeLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span> ></span><span class="hljs-tag"><<span class="hljs-title">ListView</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@android:id/list"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_above</span>=<span class="hljs-value">"@+id/commentLinearLayout"</span><span class="hljs-attribute">android:layout_alignParentTop</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:divider</span>=<span class="hljs-value">"@android:color/transparent"</span><span class="hljs-attribute">android:dividerHeight</span>=<span class="hljs-value">"15dip"</span><span class="hljs-attribute">android:scrollbars</span>=<span class="hljs-value">"none"</span> /></span><span class="hljs-tag"><<span class="hljs-title">LinearLayout</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/commentLinearLayout"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_alignParentBottom</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:background</span>=<span class="hljs-value">"#e0e0e0"</span><span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"horizontal"</span> ></span><span class="hljs-tag"><<span class="hljs-title">EditText</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/msgEditText"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"0dip"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"8"</span><span class="hljs-attribute">android:hint</span>=<span class="hljs-value">"发送消息"</span> /></span><span class="hljs-tag"><<span class="hljs-title">Button</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/msgSend"</span><span class="hljs-attribute">style</span>=<span class="hljs-value">"?android:attr/buttonStyleSmall"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"0dip"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_weight</span>=<span class="hljs-value">"2"</span><span class="hljs-attribute">android:text</span>=<span class="hljs-value">"发送"</span> /></span><span class="hljs-tag"></<span class="hljs-title">LinearLayout</span>></span><span class="hljs-tag"></<span class="hljs-title">RelativeLayout</span>></span>

ListView适配器Adapter在每一次getView时候,首先判断view的type,然后根据不同的view type加载不同的布局view。

left.xml表示是对方说的消息在ListView界面的左边:

<span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag"><<span class="hljs-title">RelativeLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"horizontal"</span> ></span><span class="hljs-tag"><<span class="hljs-title">ImageView</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/imageView"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_alignParentLeft</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:layout_centerVertical</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:singleLine</span>=<span class="hljs-value">"false"</span><span class="hljs-attribute">android:src</span>=<span class="hljs-value">"@drawable/ic_launcher"</span> /></span><span class="hljs-tag"><<span class="hljs-title">TextView</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/textView"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_centerVertical</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:layout_toRightOf</span>=<span class="hljs-value">"@+id/imageView"</span><span class="hljs-attribute">android:background</span>=<span class="hljs-value">"#ff5252"</span><span class="hljs-attribute">android:text</span>=<span class="hljs-value">"left"</span> /></span><span class="hljs-tag"></<span class="hljs-title">RelativeLayout</span>></span>

right.xml表示是自己说的消息,在消息聊天界面的右边:

<span class="hljs-pi"><?xml version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag"><<span class="hljs-title">RelativeLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"horizontal"</span> ></span><span class="hljs-tag"><<span class="hljs-title">ImageView</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/imageView"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_alignParentRight</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:layout_centerVertical</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:src</span>=<span class="hljs-value">"@drawable/ic_launcher"</span> /></span><span class="hljs-tag"><<span class="hljs-title">TextView</span><span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/textView"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span><span class="hljs-attribute">android:layout_centerVertical</span>=<span class="hljs-value">"true"</span><span class="hljs-attribute">android:layout_toLeftOf</span>=<span class="hljs-value">"@+id/imageView"</span><span class="hljs-attribute">android:background</span>=<span class="hljs-value">"#2196f3"</span><span class="hljs-attribute">android:singleLine</span>=<span class="hljs-value">"false"</span><span class="hljs-attribute">android:text</span>=<span class="hljs-value">"right"</span> /></span><span class="hljs-tag"></<span class="hljs-title">RelativeLayout</span>></span>

另外,QQ、微信这些聊天消息界面的消息背景是一个气泡,这个气泡其实是一个.9.png图片,将这个气泡的.9.png作为TextView的背景衬图衬上去即可,QQ、微信的聊天气泡.9.png不是本文要着重探讨的内容,在次不再展开叙述。

Android QQ、微信聊天消息界面设计原理与实现相关推荐

  1. android qq功能实现原理,Android QQ、微信聊天消息界面设计原理与实现

     Android QQ.微信聊天消息界面设计原理与实现 原理:Android平台上,典型的以腾讯的QQ.微信这些聊天消息界面通常可以采用ListView设计与实现,需要使用ListView 适配器 ...

  2. android 仿微信聊天界面 以及语音录制功能,Android仿微信录制语音功能

    本文实例为大家分享了Android仿微信录制语音的具体代码,供大家参考,具体内容如下 前言 我把录音分成了两部分 1.UI界面,弹窗读秒 2.一个类(包含开始.停止.创建文件名功能) 第一部分 由于6 ...

  3. Android Studio 开发–微信APP门户界面设计

    Android Studio 开发–微信APP门户界面设计 本次Github代码仓库 --crcr1013/MyWechat 文章目录 Android Studio 开发--微信APP门户界面设计 前 ...

  4. Android仿微信聊天界面

    今天说说android的仿微信聊天界面,我只想说两个字:坑爹 项目已经传到了github: https://github.com/hebiao6446/Hantu-android- 还好我写过iOS仿 ...

  5. android高仿微信聊天消息列表自由复制文字,双击查看文本内容

    SelectTextHelper-高仿微信聊天消息列表自由复制文字,双击查看文本内容 掘金地址 github地址 SelectTextHelper打造一个全网最逼近微信聊天消息自由复制,双击查看文本内 ...

  6. android放微信@功能,Android仿微信语音消息的录制和播放功能

    一.简述 效果: 实现功能: 长按Button时改变Button显示文字,弹出Dialog(动态更新音量),动态生成录音文件,开始录音: 监听手指动作,规定区域.录音状态下手指划出规定区域取消录音,删 ...

  7. android接收消息后提示音,Android仿微信新消息提示音

    怕有些人不知道怎么进入微信的新消息提示音功能,我这里说下操作步骤: 打开微信----我---设置---新消息提醒---新消息提示音. 经过以上的步骤就进入了这样的界面 具体实现的步骤. 难点之一:获取 ...

  8. android格式化时间中文版,Android 仿微信聊天时间格式化显示功能

    本文给大家分享android仿微信聊天时间格式化显示功能. 在同一年的显示规则: 如果是当天显示格式为 HH:mm 例:14:45 如果是昨天,显示格式为 昨天 HH:mm 例:昨天 13:12 如果 ...

  9. 直播间搭建实现iOS直播聊天消息界面

    直播间搭建实现iOS直播聊天消息界面 近几年直播一火再火,现在的直播已经不再是主播们唱唱歌了,连老罗都已经开始直播带货,一再刷新抖音直播在线人数了. 但今天我们不是来说怎么做直播的,是来看看直播场景里 ...

最新文章

  1. 清除浮动的几种常见方法
  2. 知道不知道 (刘若英演唱歌曲)
  3. 异或交换值(有趣点)
  4. java NIO 资料总结
  5. rocketmq 几种队列_这篇进阶必看的RocketMQ,答应我看完好吗?
  6. P3899 [湖南集训]谈笑风生
  7. Linux命令终端如何查询本机的内外网IP地址
  8. 如何获取注解中的值_如何在运行时利用注解信息
  9. python报表_Python生成报表
  10. Ajax补充之serialize
  11. linux学习笔记:如何更改文件属性?
  12. border-radius几种写法的原理剖析
  13. nginx sendfile
  14. 电脑端思维导图软件推荐
  15. linux中分号转义字符,Linux职场技术篇-Linux shell中元字符、转义符、通配符的使用方法...
  16. vue 使用 createjs 绘制扇形
  17. DFS基础-----刷题合集--1(全排列,八皇后,迷宫),让你明白DFS的基础用法
  18. Algo-131-Beaver's Calculator
  19. 中国大学MOOC C语言程序设计(大连理工大学) 课后编程题 第十一周题解(个人向仅供参考)
  20. 我在华为写了13年的代码

热门文章

  1. 运维部门工作总结_2018年度工作总结
  2. 为什么使用HashMap需要重写hashcode和equals方法_为什么要重写 hashcode 和 equals 方法?...
  3. Firefox 将导入 Windows 根证书,避免与杀毒软件的冲突
  4. 山西晋城学籍“失踪”解决方案:可参加高考或转职高
  5. 微服务小范围发布影响小
  6. linux命令---查找文件中的内容
  7. JS中定义式函数与变量时函数的差别
  8. mysql出现多线程操作同一个表的情况,应该怎么办?
  9. Xilinx ISE 调用 ModelSim SE 库编译
  10. C#正则实现匹配一块代码段