版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010316858/article/details/49488987
即时聊天控件一般采用ListView,因为ListView可以支持不同类型的item,同时ListView本身自己维护了复用机制,可以避免大量的item重复创建导致OOM,但是由于ListView复用机制所以对于编写适配器就需要避免界面混乱,在第一次做布局的时候,一个播放语音动画就导致了布局了混乱显示,所以要编写一个好的apdater去深入了解复用机制去避免界面混乱.
首先我们需要创建一个布局,布局包含了ListView,用来显示主要的对话界面:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--输入界面-->
<include
android:id="@+id/ll_input"
layout="@layout/chat_input" />
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/ll_input"
android:divider="@null" />
</RelativeLayout>
然后我们需要编写一个Adapter去设置给ListView,那么我们就要考虑用什么apdater.我们都知道SimpleAdapter支持:CheckBox,RadioButton,TextView,ImageView.而我们的需求是要编写复杂的Item,所以我们应该选择BaseAdapter.
在BaseAdapter中我们需要重写的方法:
@Override
public int getCount() {
return messages.size();
}
@Override
public Message getItem(int position) {
return messages.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return convertView;
}
上面仅仅是简述这几个基本方法,这几个基本的方法仅仅是适用于一个不变的Item,上面是一个不变的Item,?
就是单一元素的,样式大小控件个数等.为什么.?因为系统在缓存池拿去复用的控件的时候就会去判断是否单一,默认为单一,那么拿到的控件与新的Item样式大小和控件个数都不同,那么给当前的控件设置一些属性就会NullPiontException等.这也是关键所在.
所以我们还需要根据自己的需求重写2个方法,分别为:
扫描二维码关注公众号,回复:
3520154 查看本文章
@Override
public int getItemViewType(int position) {
Message message = messages.get(position);
MessageContent messageContent = message.getContent();
if (messageContent instanceof TextMessage) {// 文本
return message.getMessageDirection() == Message.MessageDirection.RECEIVE ? MESSAGE_TYPE_RECV_TXT : MESSAGE_TYPE_SENT_TXT;
} else if (messageContent instanceof ImageMessage) { // 图片
return message.getMessageDirection() == Message.MessageDirection.RECEIVE ? MESSAGE_TYPE_RECV_IMAGE : MESSAGE_TYPE_SENT_IMAGE;
} else if (messageContent instanceof LocationMessage) {// 位置
return message.getMessageDirection() == Message.MessageDirection.RECEIVE ? MESSAGE_TYPE_RECV_LOCATION : MESSAGE_TYPE_SENT_LOCATION;
} else if (messageContent instanceof RichContentMessage) {// 图文消息
return message.getMessageDirection() == Message.MessageDirection.RECEIVE ? MESSAGE_TYPE_RECV_RICH_CONTENT : MESSAGE_TYPE_SENT_RICH_CONTENT;
} else if (messageContent instanceof VoiceMessage) { // 语音消息
return message.getMessageDirection() == Message.MessageDirection.RECEIVE ? MESSAGE_TYPE_RECV_VOICE : MESSAGE_TYPE_SENT_VOICE;
} else if (messageContent instanceof InformationNotificationMessage) {//灰色提示消息
return MESSAGE_TYPE_RECV_NTF_MSG;
}
return -1;
}
@Override
public int getViewTypeCount() {
return 12;//暂时12种,后续根据业务会增加红包,广告等消息.
}
这样就避免复用的时候找到控件与对应的控件不匹配,而导致给控件设置一些属性而异常.
做完这些后我们需要真正的就是去关键的方法getView中了.在getView中我们需要使用google推荐的写法,牺牲空间去换时间,为什么要去牺牲空间换时间.?虽然ListView提供了复用机制,但是每次复用的时候你还是需要去findViewByID,而id本身就是一个二叉树,一级级的遍历非常消耗时间,所以我们还需要增加用户体验,就需要创建一个Holder,避免重复查找.
那么Holder的代码如下:
private class ViewHoder {
TextView name;//名字
ImageView head;//头像
TextView content;//文本内容
ProgressBar progressBar;//进度
ImageView state;//状态
TextView time;//消息时间
ImageView imageView;//图片消息
TextView voiceTime;//语音时间
ImageView voiceIcon;//语音图片
LinearLayout voiceGroup;//包裹语音
LinearLayout location;//包裹地图
}
这样getView的完整代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHoder viewHoder = null;
final Message message = getItem(position);
MessageContent messageContent = message.getContent();
if (null == convertView) {
viewHoder = new ViewHoder();
convertView = createViewByMessage(messages.get(position));
if (message.getContent() instanceof TextMessage) {
try {
viewHoder.time = (TextView) convertView.findViewById(R.id.chat_tv_time);
viewHoder.name = (TextView) convertView.findViewById(R.id.chat_tv_name);
viewHoder.head = (ImageView) convertView.findViewById(R.id.chat_iv_head);
viewHoder.content = (TextView) convertView.findViewById(R.id.chat_tv_content);
viewHoder.progressBar = (ProgressBar) convertView.findViewById(R.id.chat_pb);
viewHoder.state = (ImageView) convertView.findViewById(R.id.chat_iv_state);
} catch (Exception e) {
}
} else if (message.getContent() instanceof ImageMessage) {
try {
viewHoder.time = (TextView) convertView.findViewById(R.id.chat_tv_time);
viewHoder.name = (TextView) convertView.findViewById(R.id.chat_tv_name);
viewHoder.head = (ImageView) convertView.findViewById(R.id.chat_iv_head);
viewHoder.imageView = (ImageView) convertView.findViewById(R.id.chat_iv_content);
viewHoder.progressBar = (ProgressBar) convertView.findViewById(R.id.chat_pb);
viewHoder.state = (ImageView) convertView.findViewById(R.id.chat_iv_state);
} catch (Exception e) {
}
} else if (message.getContent() instanceof VoiceMessage) {
try {
viewHoder.time = (TextView) convertView.findViewById(R.id.chat_tv_time);
viewHoder.name = (TextView) convertView.findViewById(R.id.chat_tv_name);
viewHoder.head = (ImageView) convertView.findViewById(R.id.chat_iv_head);
viewHoder.voiceTime = (TextView) convertView.findViewById(R.id.chat_tv_voice_time);
viewHoder.voiceIcon = (ImageView) convertView.findViewById(R.id.chat_iv_voice);
viewHoder.voiceGroup = (LinearLayout) convertView.findViewById(R.id.chat_ll_content);
viewHoder.progressBar = (ProgressBar) convertView.findViewById(R.id.chat_pb);
viewHoder.state = (ImageView) convertView.findViewById(R.id.chat_iv_state);
} catch (Exception e) {
}
} else if (message.getContent() instanceof LocationMessage) {
try {
viewHoder.time = (TextView) convertView.findViewById(R.id.chat_tv_time);
viewHoder.name = (TextView) convertView.findViewById(R.id.chat_tv_name);
viewHoder.head = (ImageView) convertView.findViewById(R.id.chat_iv_head);
viewHoder.content = (TextView) convertView.findViewById(R.id.chat_tv_content);// 位置
viewHoder.location = (LinearLayout) convertView.findViewById(R.id.chat_ll_content);
viewHoder.progressBar = (ProgressBar) convertView.findViewById(R.id.chat_pb);
viewHoder.state = (ImageView) convertView.findViewById(R.id.chat_iv_state);
} catch (Exception e) {
}
}
convertView.setTag(viewHoder);
} else {
viewHoder = (ViewHoder) convertView.getTag();
}
handleTime(message, viewHoder, position);
//handler UserName and UserHead.
if (messageContent instanceof TextMessage) { // 文本消息
handleTextMessage(message, viewHoder, position);
} else if (messageContent instanceof ImageMessage) {// 图片消息
handleImageMessage(message, viewHoder, position);
} else if (messageContent instanceof VoiceMessage) { // 语音消息
handleVoiceMessage(message, viewHoder, position);
} else if (messageContent instanceof RichContentMessage) { // 图文消息
handleRichContentMessage(message, viewHoder, position);
} else if (messageContent instanceof InformationNotificationMessage) { // 灰色提示
handleNotifiMessage(message, viewHoder, position);
} else if (messageContent instanceof LocationMessage) { // 位置消息
handleLocationMessage(message, viewHoder, position);
} else {
//not supported.
}
return convertView;
}