1. 程式人生 > >android 仿QQ,微信群組裡的@功能,支援@多人,並能一鍵刪除,能獲取上傳對應的id(修改版)

android 仿QQ,微信群組裡的@功能,支援@多人,並能一鍵刪除,能獲取上傳對應的id(修改版)

首先註明該文章是借籤別人的部落格,原文博文地址點選開啟連結


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;
    }
}


GroupNumberListActivity

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);