UI系列教程第六课:微信聊天气泡界面的实现
今天蓝老师要给童鞋们讲的是微信聊天界面气泡的实现
如效果图所示,许多应用即时通讯的应用软件都会涉及到聊天界面
而这样的界面使用气泡的方式来呈现要比死板的方块文字更具视觉效果
而聊天内容的背景则是用点九图来处理以便自适应文本长度
(对点九图还不熟悉的童鞋请看这篇博文:http://blog.csdn.net/geniuseoe2012/article/details/7899738)
其实整体下来还是用listview+自定义baseadapter来实现
只不过传统apapter布局都是单一ITEM布局
这里则至少需要两种布局来呈现整个信息交互过程
先看看adapter的实现过程:
public class ChatMsgViewAdapter extends BaseAdapter {
public static interface IMsgViewType
{
int IMVT_COM_MSG = 0;
int IMVT_TO_MSG = 1;
}
private static final String TAG = ChatMsgViewAdapter.class.getSimpleName();
private List<ChatMsgEntity> coll;
private Context ctx;
private LayoutInflater mInflater;
public ChatMsgViewAdapter(Context context, List<ChatMsgEntity> coll) {
ctx = context;
this.coll = coll;
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return coll.size();
}
public Object getItem(int position) {
return coll.get(position);
}
public long getItemId(int position) {
return position;
}
public int getItemViewType(int position) {
// TODO Auto-generated method stub
ChatMsgEntity entity = coll.get(position);
if (entity.getMsgType())
{
return IMsgViewType.IMVT_COM_MSG;
}else{
return IMsgViewType.IMVT_TO_MSG;
}
}
public int getViewTypeCount() {
// TODO Auto-generated method stub
return 2;
}
public View getView(int position, View convertView, ViewGroup parent) {
ChatMsgEntity entity = coll.get(position);
boolean isComMsg = entity.getMsgType();
ViewHolder viewHolder = null;
if (convertView == null)
{
if (isComMsg)
{
convertView = mInflater.inflate(R.layout.chatting_item_msg_text_left, null);
}else{
convertView = mInflater.inflate(R.layout.chatting_item_msg_text_right, null);
}
viewHolder = new ViewHolder();
viewHolder.tvSendTime = (TextView) convertView.findViewById(R.id.tv_sendtime);
viewHolder.tvUserName = (TextView) convertView.findViewById(R.id.tv_username);
viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_chatcontent);
viewHolder.isComMsg = isComMsg;
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tvSendTime.setText(entity.getDate());
viewHolder.tvUserName.setText(entity.getName());
viewHolder.tvContent.setText(entity.getText());
return convertView;
}
static class ViewHolder {
public TextView tvSendTime;
public TextView tvUserName;
public TextView tvContent;
public boolean isComMsg = true;
}
}
看消息体的数据字段:
public class ChatMsgEntity {
private static final String TAG = ChatMsgEntity.class.getSimpleName();
private String name;
private String date;
private String text;
private boolean isComMeg = true;
用isComMeg来识别是外部消息还是自个儿发出去的
在getView里面根据不同类型加载不同布局:
public View getView(int position, View convertView, ViewGroup parent) {
ChatMsgEntity entity = coll.get(position);
boolean isComMsg = entity.getMsgType();
ViewHolder viewHolder = null;
if (convertView == null)
{
if (isComMsg)
{
convertView = mInflater.inflate(R.layout.chatting_item_msg_text_left, null);
}else{
convertView = mInflater.inflate(R.layout.chatting_item_msg_text_right, null);
}
viewHolder = new ViewHolder();
viewHolder.tvSendTime = (TextView) convertView.findViewById(R.id.tv_sendtime);
viewHolder.tvUserName = (TextView) convertView.findViewById(R.id.tv_username);
viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_chatcontent);
viewHolder.isComMsg = isComMsg;
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.tvSendTime.setText(entity.getDate());
viewHolder.tvUserName.setText(entity.getName());
viewHolder.tvContent.setText(entity.getText());
return convertView;
}
众所周知,listview要充分运用到缓存试图convertView,否则一旦数据量大了很容易造成OOM异常,而我们的adaper里有用到两种视图布局,又该如何去重复利用呢?
乾坤在这里:
public int getItemViewType(int position) {
// TODO Auto-generated method stub
ChatMsgEntity entity = coll.get(position);
if (entity.getMsgType())
{
return IMsgViewType.IMVT_COM_MSG;
}else{
return IMsgViewType.IMVT_TO_MSG;
}
}
public int getViewTypeCount() {
// TODO Auto-generated method stub
return 2;
}
getItemViewType用来识别视图类型
getViewTypeCount标识视图类型数量
这样每次缓存下来的视图就总是能传递正确的对象去重复利用了
最后再贴一个item的布局出来:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="6dp">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal">
<TextView
android:id="@+id/tv_sendtime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/chat_text_date_style"/>
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp" >
<ImageView
android:id="@+id/iv_userhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="@drawable/mini_avatar_shadow"/>
<TextView
android:id="@+id/tv_chatcontent"
android:layout_toRightOf="@id/iv_userhead"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/chatfrom_bg"
style="@style/chat_content_date_style"/>
<TextView
android:id="@+id/tv_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/iv_userhead"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/tv_chatcontent"
style="@style/chat_text_name_style"/>
</RelativeLayout>
</LinearLayout>
附上链接工程:
http://download.csdn.net/detail/geniuseoe2012/4536804
欲知更多Android-UI技巧,请关注窝的下一堂课,更多精彩尽在http://blog.csdn.net/geniuseoe2012
welcome to join android develop group:298044305
上一课:Lance老师UI系列教程第五课->自定义风格单选多选对话框的实现
下一课:Lance老师UI系列教程第七课->自定义spinner下拉框实现的实现