先介绍BaseHolder类,这个类是聊天类型的控件载体,包含通用的contentview,由initBaseHolder里面的参数传递
public class BaseHolder { /** * row type {@link ChattingRowType} */ protected int type; /** * for upload message . */ protected ProgressBar progressBar; protected ImageView chattingAvatar; protected TextView chattingTime; protected TextView chattingUser; protected ImageView uploadState; protected View baseView; protected View clickAreaView; public BaseHolder(int type) { this.type = type; } /** * @param baseView */ public BaseHolder(View baseView) { super(); this.baseView = baseView; } public void initBaseHolder(View baseView) { this.baseView = baseView; chattingTime = (TextView) baseView.findViewById(R.id.chatting_time_tv); chattingAvatar = (ImageView) baseView.findViewById(R.id.chatting_avatar_iv); clickAreaView = baseView.findViewById(R.id.chatting_click_area); uploadState = (ImageView) baseView.findViewById(R.id.chatting_state_iv); } /** * @return the baseView */ public View getBaseView() { return baseView; } /** * @return the type */ public int getType() { return type; } /** * @return the progressBar */ public ProgressBar getUploadProgressBar() { return progressBar; } /** * @return the chattingAvatar */ public ImageView getChattingAvatar() { return chattingAvatar; } /** * @return the chattingTime */ public TextView getChattingTime() { return chattingTime; } /** * @param chattingTime the chattingTime to set */ public void setChattingTime(TextView chattingTime) { this.chattingTime = chattingTime; } /** * @return the chattingUser */ public TextView getChattingUser() { return chattingUser; } /** * @return the uploadState */ public ImageView getUploadState() { return uploadState; } /** * @return the clickAreaView */ public View getClickAreaView() { return clickAreaView; } }
再看他的子类CardViewHolder,initBaseHolder方法中条用父类的initBaseHolder加载的通用控件,在扩展了自己的新增控件
public class CardViewHolder extends BaseHolder{ private TextView content; private TextView nick; private ImageView avatar; private LinearLayout ll_click; public LinearLayout getLl_click() { if(ll_click==null){ ll_click = (LinearLayout)baseView.findViewById(R.id.bg_ll); } return ll_click; } public ImageView getAvatar() { if(avatar==null){ avatar = (ImageView)baseView.findViewById(R.id.avatar); } return avatar; } public TextView getContent() { if(content==null){ content =(TextView) baseView.findViewById(R.id.content); } return content; } public TextView getNick() { if(nick==null){ nick = (TextView)baseView.findViewById(R.id.nick); } return nick; } public CardViewHolder(int type) { super(type); } public BaseHolder initBaseHolder(View baseView , boolean receive) { super.initBaseHolder(baseView);//父类通用控件,以下为扩展的控件 content =(TextView) baseView.findViewById(R.id.content); nick = (TextView)baseView.findViewById(R.id.nick); avatar = (ImageView)baseView.findViewById(R.id.avatar); ll_click = (LinearLayout)baseView.findViewById(R.id.bg_ll); return this; } }以上为各个item对应holder控件,以下是用数据实例化holder里面控件的接口类public interface IChattingRow { /** * 获取实例的convertView,由具体的item子类重写实现,并给具体的子类的convertView设置tag为子类的holder以供复用*/ View buildChatView(LayoutInflater inflater, View convertView); /** *给baseHolder里面的控件填充数据 */ void buildChattingBaseData(Context context, BaseHolder baseHolder, ECMessage detail, int position); /** * @return 返回具体的item类型,有具体子类实现 */ int getChatViewType(); }接下来写一个abstract类来实现IChattingRow接口,这个类为所有item通用的控件填充数据public abstract class BaseChattingRow implements IChattingRow { int mRowType; public BaseChattingRow(int type) { mRowType = type; } /** * 处理消息的发送状态设置 * * @param position * 消息的列表所在位置 * @param holder * 消息ViewHolder * @param l */ protected static void getMsgStateResId(int position, BaseHolder holder, ECMessage msg, View.OnClickListener l) { if (msg != null && msg.getDirection() == ECMessage.Direction.SEND) { ECMessage.MessageStatus msgStatus = msg.getMsgStatus(); if (msgStatus == ECMessage.MessageStatus.FAILED) { holder.getUploadState().setImageResource( R.drawable.msg_state_failed_resend); holder.getUploadState().setVisibility(View.VISIBLE); if (holder.getUploadProgressBar() != null) { holder.getUploadProgressBar().setVisibility(View.GONE); } } else if (msgStatus == ECMessage.MessageStatus.SUCCESS || msgStatus == ECMessage.MessageStatus.RECEIVE) { holder.getUploadState().setImageResource(0); holder.getUploadState().setVisibility(View.GONE); if (holder.getUploadProgressBar() != null) { holder.getUploadProgressBar().setVisibility(View.GONE); } } else if (msgStatus == ECMessage.MessageStatus.SENDING) { holder.getUploadState().setImageResource(0); holder.getUploadState().setVisibility(View.GONE); if (holder.getUploadProgressBar() != null) { holder.getUploadProgressBar().setVisibility(View.VISIBLE); } } else { if (holder.getUploadProgressBar() != null) { holder.getUploadProgressBar().setVisibility(View.GONE); } LogUtil.d(TAG, "getMsgStateResId: not found this state"); } ViewHolderTag holderTag = ViewHolderTag.createTag(msg, ViewHolderTag.TagType.TAG_RESEND_MSG, position); holder.getUploadState().setTag(holderTag); holder.getUploadState().setOnClickListener(l); } } protected abstract void buildChattingData(Context context, BaseHolder baseHolder, ECMessage detail, int position);//填充扩展的holder里面控件的数据,由具体子类实现 @Override public void buildChattingBaseData(Context context, BaseHolder baseHolder, ECMessage detail, int position) { // 处理其他使用逻辑 buildChattingData(context, baseHolder, detail, position);String sid = detail.getSessionId(); String avatar = ""; String nick = ""; if (detail.getDirection() == ECMessage.Direction.SEND) {//如果是信息发送出去,则处理自己头像和昵称数据} else {//如果是接收的别人的信息,则处理对方头像和昵称数据
} //填充头像,昵称,以及通用的点击事件 // 头像 setContactPhoto(baseHolder, avatar); // 昵称 setDisplayName(baseHolder, nick); // 头像点击事件 setContactPhotoClickListener(context, baseHolder, detail); } private void setContactPhotoClickListener(final Context context, BaseHolder baseHolder, final ECMessage detail) { if (baseHolder.getChattingAvatar() != null && detail != null) { baseHolder.getChattingAvatar().setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { } }); } } public static void setDisplayName(BaseHolder baseHolder, String displayName) { if (baseHolder == null || baseHolder.getChattingUser() == null) { return; } if (TextUtils.isEmpty(displayName)) { baseHolder.getChattingUser().setVisibility(View.GONE); return; } baseHolder.getChattingUser().setText(displayName); baseHolder.getChattingUser().setVisibility(View.VISIBLE); } /** * 添加用户头像 * * @param baseHolder */ private void setContactPhoto(BaseHolder baseHolder, String avatar) { if (baseHolder.getChattingAvatar() != null) { try { ImageUtils.setHeadImage(avatar, baseHolder.getChattingAvatar()); } catch (Exception e) { } } } }以下为具体的实现类public class SendTCardRow extends BaseChattingRow{ public SendTCardRow(int type) { super(type); } @Override protected void buildChattingData(final Context context, BaseHolder baseHolder, ECMessage detail, int position) {//填充扩展数据 CardViewHolder holder = (CardViewHolder) baseHolder; ECMessage message = detail; if(message != null && message.getType() == ECMessage.Type.TXT){ if(message.getDirection()==ECMessage.Direction.SEND){ holder.getContent().setText("已向对方推荐个人名片"); }else { holder.getContent().setText("对方向您推荐个人名片"); } String jstr = message.getUserData(); final JSONObject obj = (JSONObject) JSONObject.parse(jstr); ImageUtils.setHeadImage((String) obj.get("avatar"),holder.getAvatar()); holder.getNick().setText((String) obj.get("nick")); holder.getLl_click().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } }); } } @Override public View buildChatView(LayoutInflater inflater, View convertView) {//获取具体化的itemView if (convertView == null) { convertView = new ChattingItemContainer(inflater, R.layout.chatting_item_send_card); CardViewHolder holder = new CardViewHolder(mRowType); convertView.setTag(holder.initBaseHolder(convertView, true)); } return convertView; } @Override public int getChatViewType() {//获取Item的类型 return ChattingRowType.SEND_TCARD_ROW.ordinal(); } }以下为不同的item类型的枚举类public enum ChattingRowType { /** * display a image of message received */ IMAGE_ROW_RECEIVED("C200R" , Integer.valueOf(1)), /** * display a image of message transmitted */ IMAGE_ROW_TRANSMIT("C200T" , Integer.valueOf(2)), /** * display a file of message received */ FILE_ROW_RECEIVED("C1024R" , Integer.valueOf(3)), /** * display a file of message transmitted */ FILE_ROW_TRANSMIT("C1024T" , Integer.valueOf(4)), /** * display a voice of message received */ VOICE_ROW_RECEIVED("C60R" , Integer.valueOf(5)), /** * display a voice of message transmitted */ VOICE_ROW_TRANSMIT("C60T" , Integer.valueOf(6)), /** * Display text of message received */ DESCRIPTION_ROW_RECEIVED("C2000R" , Integer.valueOf(7)), /** * Display text of message transmitted */ DESCRIPTION_ROW_TRANSMIT("C2000T" , Integer.valueOf(8)), /** * chatting item for system .such as time */ CHATTING_SYSTEM("C18600668603R" , Integer.valueOf(9)), LOCATION_ROW_RECEIVED("C2200R" , Integer.valueOf(10)), LOCATION_ROW_TRANSMIT("C2200T" , Integer.valueOf(11)), CALL_ROW_RECEIVED("C2400R" , Integer.valueOf(12)), CALL_ROW_TO("C2400T" , Integer.valueOf(13)), // CALL_ROW_TRANSMIT("C2400T" , Integer.valueOf(13)); ADD_ROW("1011" , Integer.valueOf(14)), ADD_RESULT_ROW("1012" , Integer.valueOf(15)), ADD_HELP_ROW("1015" , Integer.valueOf(16)), ADD_HELP_RESULT_ROW("1016" , Integer.valueOf(17)), SEND_TCARD_ROW("1019",Integer.valueOf(19)), SEND_THELP_ROW("1020",Integer.valueOf(20)), SEND_REDBAGS_ROW("2000",Integer.valueOf(21)),//发红包 SEND_KITE_ROW("2001",Integer.valueOf(22)),//发礼物 SHARE_SHOW_ROW("2002",Integer.valueOf(23));//发礼物 private final Integer mId; private final Object mDefaultValue; /** * Constructor of <code>ChattingRowType</code>. * * @param id The unique identifier of the setting * @param defaultValue The default value of the setting */ private ChattingRowType(Object defaultValue , Integer id) { this.mId = id; this.mDefaultValue = defaultValue; } /** * Method that returns the unique identifier of the setting. * @return the mId */ public Integer getId() { return this.mId; } /** * Method that returns the default value of the setting. * * @return Object The default value of the setting */ public Object getDefaultValue() { return this.mDefaultValue; } /** *通过value(类型的字段代号)获取对应的类型 */ public static ChattingRowType fromValue(String value) { ChattingRowType[] values = values(); int cc = values.length; for (int i = 0; i < cc; i++) { if (values[i].mDefaultValue.equals(value)) { return values[i]; } } return null; } }接下来就是重点了,怎么在适配器adapter中配置不同类型的convertView;重点看getView 方法@Override public View getView(int position, View convertView, ViewGroup parent) { ECMessage item = getItem(position); if (item == null) { return null; } boolean showTimer = false; if (position == 0) { showTimer = true; } if (position != 0) {//是否显示时间 ECMessage previousItem = getItem(position - 1); if (mShowTimePosition.contains(item.getMsgId()) || (item.getMsgTime() - previousItem.getMsgTime() >= 180000L)) { showTimer = true; } } BaseChattingRow chattingRow; String msgT = ""; if (item.getType() == ECMessage.Type.TXT && !TextUtils.isEmpty(item.getUserData())) {//自己扩展的消息类型 try { JSONObject map = JSONObject.parseObject(item.getUserData()); msgT = map.getString("msg_type"); String video_id = map.getString("video_id"); String nick = map.getString("nick"); } catch (JSONException e) { } chattingRow = getBaseChattingRow(msgT, item.getDirection() == ECMessage.Direction.SEND);//根据消息类型扩展字段获取到对应的消息类型 } else {//第三方SDK自带的消息类型 int messageType = ChattingsRowUtils.getChattingMessageType(item .getType());//获取第三方SDK自带的消息类型代号 chattingRow = getBaseChattingRow(messageType, item.getDirection() == ECMessage.Direction.SEND); } View chatView = chattingRow.buildChatView( LayoutInflater.from(mContext), convertView);//给对应的消息类型填充布局,并设置了tag BaseHolder baseHolder = (BaseHolder) chatView.getTag();//根据tag获取对应的holder chattingRow.buildChattingBaseData(mContext, baseHolder, item, position);//给对应的holder填充控件数据 return chatView; }/** * 根据消息类型返回相对应的自带消息Item * * @param rowType * @param isSend * @return */ public BaseChattingRow getBaseChattingRow(int rowType, boolean isSend) { StringBuilder builder = new StringBuilder("C").append(rowType); if (isSend) { builder.append("T"); } else { builder.append("R"); } LogUtil.d("ChattingListAdapter", "builder.toString() = " + builder.toString()); ChattingRowType fromValue = ChattingRowType.fromValue(builder .toString()); LogUtil.d("ChattingListAdapter", "fromValue = " + fromValue); IChattingRow iChattingRow = mRowItems.get(fromValue.getId().intValue()); return (BaseChattingRow) iChattingRow; } /** * 获取扩展消息类型 * @param isSend * @return */ public BaseChattingRow getBaseChattingRow(String msgT, boolean isSend) { ChattingRowType fromValue = ChattingRowType.fromValue(msgT); if(fromValue!=null){ IChattingRow iChattingRow = mRowItems.get(fromValue.getId() .intValue()); return (BaseChattingRow) iChattingRow; } return null; }public class ChattingsRowUtils { /** * * @param type * @return */ public static int getChattingMessageType(ECMessage.Type type) { if(type == ECMessage.Type.TXT) { return 2000; } else if (type == ECMessage.Type.VOICE) { return 60; } else if (type == ECMessage.Type.FILE) { return 1024; } else if (type == ECMessage.Type.IMAGE) { return 200; }else if(type==ECMessage.Type.VIDEO){ return 1024; }else if(type==ECMessage.Type.LOCATION){ return 2200; }else if(type== ECMessage.Type.CALL){ return 2400; } return 2000; } 嗯,代码有点多,重点记住标注的方法和面向对象思路