android 仿QQ,微信群組裡的@功能,支援@多人,並能一鍵刪除,能獲取上傳對應的id(修改版)
阿新 • • 發佈:2018-12-21
首先註明該文章是借籤別人的部落格,原文博文地址點選開啟連結
android 仿QQ,微信群組裡的@功能,支援@多人,並能一鍵刪除,能獲取上傳對應的id
這個需求來源:本人做整合環信聊天時,專案需要@功能,但是環信並沒有提供@功能。環信@功能地址點選開啟連結
輸入@符號之後進入好友列表
點選某個人,返回這個人的資訊,並以@xxx的格式顯示在 EditText 中
@部分需要變色
刪除的時候需要把“@xxx”整體直接刪除
基於以上幾點要求,我有個想法:
通過InputFilter判斷使用者輸入,當有“@”符號輸入時,跳轉到好友列表頁,返回使用者資訊之後,把文字轉換成bitmap,用SpannableString 做實現後面的功能
UXchatActivity
package ucux.app.activitys; import android.os.Bundle; import android.text.Spanned; import ucux.app.R; public class UXchatActivity extends BaseActivity implements OnClickListener { public static final int RESULT_CODE_SEND_MEMBER = 32; private EditText mEditTextContent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mEditTextContent = (EditText) findViewById(R.id.et_sendmessage); mEditTextContent.setFilters(new InputFilter[]{new MyInputFilter()}); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == RESULT_CODE_SEND_MEMBER) {// @群成員 UxChatUtils.sendMember(this, data, cidNameMap, mEditTextContent); } } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btn_send:// 點擊發送按鈕(發文字和表情) mChatManager.sendText(s, mPMSessionResult.getPMSID(), UxChatUtils.getAtMemberList(mEditTextContent, cidNameMap)); cidNameMap.clear();// 傳完之後清空一下@的列表 break; } } // @群組成員 /** * 儲存@的cid、name對 */ private Map<String, String> cidNameMap = new HashMap<>(); /** * 識別輸入框的是不是@符號 */ private class MyInputFilter implements InputFilter { @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { if (source.toString().equalsIgnoreCase("@") || source.toString().equalsIgnoreCase("@")) { if (currentChatType() == 2)// 群聊,才能@群組成員 goAt(); } return source; } } private void goAt() { Intent intent = new Intent(UXchatActivity.this, GroupNumberListActivity.class); intent.putExtra("PMSID", mPMSessionResult.getPMSID()); intent.putExtra("SEMDMEMBER", true); startActivityForResult(intent, RESULT_CODE_SEND_MEMBER); } private View.OnLongClickListener longClickListener = new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { try { switch (view.getId()) { case R.id.iv_userhead: EMPM empm = (EMPM) view.getTag(R.id.tag_send_member); Forward lForward = MessageTranslateUtil.TranformForward(empm); if ((currentChatType() == 2) && (lForward != null) && (empm.direct()) && (!UxChatUtils.isExistInMemberList(cidNameMap, lForward.getUID()))) {// 群聊 Intent intent = new Intent(); intent.putExtra(GroupNumberListActivity.KEY_UID, lForward.getUID() + " "); intent.putExtra(GroupNumberListActivity.KEY_NAME, "@" + lForward.getName() + " "); UxChatUtils.sendMember(UXchatActivity.this, intent, cidNameMap, mEditTextContent); } else { return false; } break; } } catch (Exception e) { e.printStackTrace(); } return true; } }; }
UxChatUtils
/** * 聊天工具類(新增的) * Created by Administrator on 2017/3/2. */ public class UxChatUtils { //上傳需要的uid值 public static ArrayList<String> getAtMemberList(EditText mEditText, Map<String, String> cidNameMap) { ArrayList<String> atMembers = new ArrayList<>(); ArrayList<String> list = new ArrayList<>(); String content = String.valueOf(mEditText.getText().toString().trim()); String[] sss = content.split(" "); for (String s : sss) { list.add(s); } for (int i = 0; i < list.size(); i++) { String keys = ""; Iterator it = cidNameMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Object obj = entry.getValue(); if (obj != null && list.get(i).contains((String) obj)) { keys = (String) entry.getKey(); } } if (!TextUtils.isEmpty(keys)) atMembers.add(keys); } return atMembers; } /** * 返回的所有的使用者名稱,用於識別輸入框中的所有要@的人 * 如果使用者刪除過,會出現不匹配的情況,需要在for迴圈中做處理 */ private static String nameStr; /** * 上一次返回的使用者名稱,用於把要@的使用者名稱拼接到輸入框中 */ private static String lastNameStr; public static void sendMember(Context context, Intent data, Map<String, String> cidNameMap, EditText mEditText) { String tmpCidStr = data.getStringExtra(GroupNumberListActivity.KEY_UID); String tmpNameStr = data.getStringExtra(GroupNumberListActivity.KEY_NAME); String[] tmpCids = tmpCidStr.split(" "); String[] tmpNames = tmpNameStr.split(" "); if (tmpCids.length > 0) { for (int i = 0; i < tmpCids.length; i++) { if (tmpNames.length > i) { cidNameMap.put(tmpCids[i], tmpNames[i]); } } } // 這裡的lists集合,是把輸入框裡已經有的人名放進集合中,再在一個一個的比較選擇返回的人名,如果是一樣的就return,並且不再顯示到輸入框 ArrayList<String> lists = new ArrayList<String>(); String content = String.valueOf(mEditText.getText().toString().trim()); String[] ssss = content.split(" "); Collections.addAll(lists, ssss); for (int i = 0; i < lists.size(); i++) { if (lists.get(i).equals(tmpNameStr.trim())) { int curIndex = mEditText.getSelectionStart(); if (curIndex >= 1) { mEditText.getText().replace(curIndex - 1, curIndex, ""); } return; } } //返回的人名,自增加 if (nameStr == null) { nameStr = tmpNameStr; } else { nameStr = nameStr + tmpNameStr; } lastNameStr = tmpNameStr; // 獲取游標當前位置 int curIndex = mEditText.getSelectionStart(); // 把要@的人插入游標所在位置 mEditText.getText().insert(curIndex, lastNameStr); // 通過輸入@符號進入好友列表並返回@的人,要刪除之前輸入的@ if (curIndex >= 1) { mEditText.getText().replace(curIndex - 1, curIndex, ""); } setAtImageSpan(context, mEditText, nameStr); } private static void setAtImageSpan(final Context context, EditText mEditText, String nameStr) { String content = String.valueOf(mEditText.getText()); if (content.endsWith("@") || content.endsWith("@")) { content = content.substring(0, content.length() - 1); } String tmp = content; SpannableString ss = new SpannableString(tmp); if (nameStr != null) { String[] names = nameStr.split(" "); if (names.length > 0) { for (String name : names) { if (name != null && name.trim().length() > 0) { //把獲取到的名字轉為bitmap物件 final Bitmap bmp = getNameBitmap(context, name); // 這裡會出現刪除過的使用者,需要做判斷,過濾掉 if (tmp.contains(name) && (tmp.indexOf(name) + name.length()) <= tmp.length()) { // 把取到的要@的人名,用DynamicDrawableSpan代替 ss.setSpan(new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) { @Override public Drawable getDrawable() { BitmapDrawable drawable = new BitmapDrawable(context.getResources(), bmp); drawable.setBounds(0, 0, bmp.getWidth(), bmp.getHeight()); return drawable; } }, tmp.indexOf(name), tmp.indexOf(name) + name.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); } } } } } mEditText.setTextKeepState(ss); } /** * 把返回的人名,轉換成bitmap * * @param name 人名 * @return 圖片 */ private static Bitmap getNameBitmap(Context context, String name) { /* 把@相關的字串轉換成bitmap 然後使用DynamicDrawableSpan加入輸入框中 */ name = "" + name; Paint paint = new Paint(); paint.setAntiAlias(true); // 設定字型畫筆的顏色 // paint.setColor(context.getResources().getColor(R.color.transculent_black)); paint.setTextSize(30); Rect rect = new Rect(); paint.getTextBounds(name, 0, name.length(), rect); // 獲取字串在螢幕上的長度 int width = (int) (paint.measureText(name)); final Bitmap bmp = Bitmap.createBitmap(width + 5, rect.height() + 5, Bitmap.Config.ARGB_8888);// 長寬+5,可調 Canvas canvas = new Canvas(bmp); canvas.drawColor(context.getResources().getColor(R.color.color_primary)); canvas.drawText(name, rect.left, rect.height() - rect.bottom, paint); return bmp; } /** * 群組成員列表中是否已經有相應的uid * * @param cidNameMap cidNameMap * @param uid uid * @return true-->有 */ public static boolean isExistInMemberList(Map<String, String> cidNameMap, long uid) { try { for (Object o : cidNameMap.entrySet()) { Map.Entry entry = (Map.Entry) o; Object key = entry.getKey(); if (Long.parseLong(key.toString()) == uid) return true; } } catch (Exception e) { e.printStackTrace(); } return false; } }
if (getIntent().getBooleanExtra("SEMDMEMBER", false)){
// 傳回群成員相關資訊,並且關閉頁面
Intent intent = new Intent();
intent.putExtra(KEY_UID, String.valueOf(mPMSMemberList.get(position).getUID()) + " ");
intent.putExtra(KEY_NAME, "@" + mPMSMemberList.get(position).getUName() + " ");
setResult(RESULT_OK, intent);
finish();
}
在adapter中的頭像設定長按監聽,長按頭像就@那個成員
holder.iv_avatar.setTag(R.id.tag_send_member, message);
holder.iv_avatar.setOnLongClickListener(longClickListener);