首先注明该文章是借签别人的博客,原文博文地址点击打开链接
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);