package com.netease.nim.uikit.contact.core.viewholder; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import com.netease.nim.uikit.R; import com.netease.nim.uikit.cache.TeamDataCache; import com.netease.nim.uikit.common.ui.imageview.HeadImageView; import com.netease.nim.uikit.common.util.sys.ScreenUtil; import com.netease.nim.uikit.common.util.sys.TimeUtil; import com.netease.nim.uikit.contact.core.item.MsgItem; import com.netease.nim.uikit.contact.core.model.ContactDataAdapter; import com.netease.nim.uikit.contact.core.model.IContact; import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; import com.netease.nimlib.sdk.search.model.MsgIndexRecord; import com.netease.nimlib.sdk.search.model.RecordHitInfo; import com.netease.nimlib.sdk.team.model.Team; import java.util.List; public class MsgHolder extends AbsContactViewHolder<MsgItem> { private static final String PREFIX = "..."; protected HeadImageView head; protected TextView name; protected TextView time; protected TextView desc; protected int descTextViewWidth; // 当前ViewHolder desc TextView 最大的宽度px @Override public View inflate(LayoutInflater inflater) { View view = inflater.inflate(R.layout.nim_contacts_item, null); head = (HeadImageView) view.findViewById(R.id.contacts_item_head); name = (TextView) view.findViewById(R.id.contacts_item_name); time = (TextView) view.findViewById(R.id.contacts_item_time); desc = (TextView) view.findViewById(R.id.contacts_item_desc); // calculate View parent = (View) desc.getParent(); if (parent.getMeasuredWidth() == 0) { // xml中:50dp,包括头像的长度还有左右间距大小 parent.measure(View.MeasureSpec.makeMeasureSpec(ScreenUtil.getDisplayWidth() - ScreenUtil.dip2px(50.0f), View.MeasureSpec.EXACTLY), 0); } descTextViewWidth = (int) (parent.getMeasuredWidth() - desc.getPaint().measureText(PREFIX)); return view; } @Override public void refresh(ContactDataAdapter adapter, int position, final MsgItem item) { // contact info final IContact contact = item.getContact(); final MsgIndexRecord record = item.getRecord(); if (record.getSessionType() == SessionTypeEnum.P2P) { head.loadBuddyAvatar(contact.getContactId()); } else { Team team = TeamDataCache.getInstance().getTeamById(contact.getContactId()); head.loadTeamIconByTeam(team); } name.setText(contact.getDisplayName()); if (item.isQuerySession()) { time.setVisibility(View.VISIBLE); time.setText(TimeUtil.getTimeShowString(record.getTime(), false)); } else { time.setVisibility(View.GONE); } // query result if (record.getCount() > 1) { desc.setText(String.format("%d条相关聊天记录", record.getCount())); } else { String text = record.getText(); // 原串 List<RecordHitInfo> clone = record.cloneHitInfo(); // 计算高亮区域并clone // 异常情况,没有高亮击中的区间,直接设置原串 if (clone == null || clone.isEmpty()) { desc.setText(text); return; } int firstIndex = clone.get(0).start; // 首个需要高亮的关键字的起始位置 int firstHitInfoLength = clone.get(0).end - clone.get(0).start + 1; // 首个需要高亮的关键字的长度 // 判断是否需要截取 Object[] result = needCutText(record.getText(), firstIndex, firstHitInfoLength); Boolean needCut = (Boolean) result[0]; int extractPreStrNum = (Integer) result[1]; if (needCut) { // 文本截取 int newStartIndex = firstIndex - extractPreStrNum; text = PREFIX + text.substring(newStartIndex); // 矫正hitInfo int delta = newStartIndex - PREFIX.length(); for (RecordHitInfo rh : clone) { rh.start -= delta; rh.end -= delta; } } display(desc, text, clone); } } /** * 假如第一个索引之前的文字宽度>layout宽度,就需要把text截断 * * @param text 原文本 * @param firstIndex 首个需要高亮的关键字的起始位置 * @param firstHitInfoLength 首个需要高亮的关键字的长度 * @return [0]是否需要截取字符串;[1]如果要截取,那么需要提取前面几个字符 */ private Object[] needCutText(String text, int firstIndex, int firstHitInfoLength) { Boolean r0; Integer r1; float descLength = desc.getPaint().measureText(text.substring(0, firstIndex + firstHitInfoLength)); float avg = descLength / (firstIndex + firstHitInfoLength); // 前firstIndex+firstHitInfoLength个字符,平均每个字符的长度 if (descLength >= descTextViewWidth) { r0 = true; int extractPreStrNum = (int) (1.0f * descTextViewWidth / avg); // 当前viewHolder desc TextView能容纳多少个字符(前firstIndex区间的字符) extractPreStrNum = extractPreStrNum - PREFIX.length() - firstHitInfoLength; // 可以提取前面几个字符 if (extractPreStrNum < 0) { extractPreStrNum = 0; // 有可能为负数,例如firstHitInfo特别长 } // 新的文本 int newStartIndex = firstIndex - extractPreStrNum; text = PREFIX + text.substring(newStartIndex, firstIndex + firstHitInfoLength); // extractPreStrNum 校准 if (extractPreStrNum > 0) { descLength = desc.getPaint().measureText(text); if (descLength > descTextViewWidth) { int delta = (int) ((descLength - descTextViewWidth) / (descLength / text.length())) + 1; extractPreStrNum -= delta; // 減少提取的字符数 } if (extractPreStrNum < 0) { extractPreStrNum = 0; // 修正 } } r1 = extractPreStrNum; } else { r0 = false; r1 = 0; } return new Object[]{r0, r1}; } public static final void display(TextView tv, String text, List<RecordHitInfo> hitInfos) { if (hitInfos == null || hitInfos.isEmpty()) { tv.setText(text); return; } SpannableStringBuilder sb = new SpannableStringBuilder(); SpannableString ss = new SpannableString(text); for (RecordHitInfo r : hitInfos) { ss.setSpan(new ForegroundColorSpan(tv.getResources().getColor(R.color.contact_search_hit)), r.start, r.end + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } sb.append(ss); tv.setText(sb); } }