Android QQ、微信聊天消息界面设计原理与实现
2016-08-05 15:07
991 查看
原理:Android平台上,典型的以腾讯的QQ、微信这些聊天消息界面通常可以采用ListView设计与实现,需要使用ListView 适配器Adapter的getItemViewType()和getViewTypeCount()。
在ListView的适配器中,每一次getView时候,首先要判断view的类型getItemViewType(),然后根据不同的类型加载不同的布局view。
至于底部发送消息的窗口,每次发送完消息,需要将ListView滚动到底部,以免输入键盘遮挡住数据而致使用户看不到刚刚发送的消息。
现在给出一个Android平台上简单的设计与实现方案。效果如图所示:
![](http://img.voidcn.com/vcimg/000/003/021/355_fff_d6e.jpg)
测试的主Activity MainActivity.java:
MainActivity.java需要的布局文件activity_main.xml:
ListView适配器Adapter在每一次getView时候,首先判断view的type,然后根据不同的view type加载不同的布局view。
left.xml表示是对方说的消息在ListView界面的左边:
right.xml表示是自己说的消息,在消息聊天界面的右边:
另外,QQ、微信这些聊天消息界面的消息背景是一个气泡,这个气泡其实是一个.9.png图片,将这个气泡的.9.png作为TextView的背景衬图衬上去即可,QQ、微信的聊天气泡.9.png不是本文要着重探讨的内容,在次不再展开叙述。
原理:Android平台上,典型的以腾讯的QQ、微信这些聊天消息界面通常可以采用ListView设计与实现,需要使用ListView 适配器Adapter的getItemViewType()和getViewTypeCount()。
在ListView的适配器中,每一次getView时候,首先要判断view的类型getItemViewType(),然后根据不同的类型加载不同的布局view。
至于底部发送消息的窗口,每次发送完消息,需要将ListView滚动到底部,以免输入键盘遮挡住数据而致使用户看不到刚刚发送的消息。
现在给出一个Android平台上简单的设计与实现方案。效果如图所示:
![](http://img.voidcn.com/vcimg/000/003/021/355_fff_d6e.jpg)
测试的主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、微信聊天消息界面设计原理与实现
- 仿微信、短信、QQ等消息数目右上角红色小圆球气泡显示(基于Android XML布局文件实现)
- Android仿微信气泡聊天界面设计(二)
- Android仿微信气泡聊天界面设计
- android 自定义listview实现仿微信/QQ设置界面的开发
- Android仿微信气泡聊天界面设计
- Android 仿微信QQ聊天界面
- UI设计之【android 仿微信、QQ聊天,带表情,可翻页,带翻页拖动缓冲】
- 转-Android仿微信气泡聊天界面设计
- Android 仿微信QQ聊天界面
- 仿微信、短信、QQ等消息数目右上角红色小圆球气泡显示(基于Android XML布局文件实现)
- iOS中QQ聊天界面发送消息及表情键盘的实现
- 【android】软键盘 - 仿 qq/微信 聊天界面布局
- 实现类似QQ、微信聊天界面,标题栏固定,键盘不遮挡底部输入框
- Android学习之仿QQ聊天界面的实现
- iOS 类似微信,QQ聊天界面的气泡聊天简单实现Demo
- android 实现微信聊天界面效果
- Android仿微信气泡聊天界面设计 天气取数据uri
- Android仿微信气泡聊天界面设计
- Android仿微信气泡聊天界面设计