首先注明该文章是借签别人的博客,原文博文地址点击打开链接

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;@Overrideprotected 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);}}@Overridepublic 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 {@Overridepublic 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() {@Overridepublic 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) {@Overridepublic 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);

android 仿QQ,微信群组里的@功能,支持@多人,并能一键删除,能获取上传对应的id(修改版)相关推荐

  1. Android仿QQ微信开场导航以及登陆界面

    相信大家对于微信等社交应用的UI界面已经都很熟悉了,该UI最值得借鉴的莫过于第一次使用的时候一些列产品介绍的图片,可以左右滑动浏览,最后进入应用,这一效果适用于多种项目中,相信今后开发应用一定会用得到 ...

  2. android qq语音按钮,Android 仿QQ/微信语音功能。

    简单仿照一个语音效果,效果图: 所以,首先先做一个Dialog用于展示我们说话的UI: VoiceDialogManager.java /** * 语音Dialog 管理器 * Created by ...

  3. 一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片

    说点题外话. Coding中我们总是经历着这么几个过程. 学会使用: 不管是API也好, 开源库也好. 总是在最开始的学会去用. 了解实现原理: 可能会因为一些不兼容, 代码的异常状态的处理不够完美等 ...

  4. 仿微信群组头像组合边框实现

    由于项目需要展示头像跟微信群组那样的组合,网上搜了一堆都不太符合要求,额,可能没有找到吧 下面就分享一个自己整合的头像合成工具类: 先说一下实现思路和步骤: (1)首先要创建一张空白的大图片 (2)根 ...

  5. Android仿QQ通讯录分组展示ExpandableListView

    Android仿QQ通讯录分组展示ExpandableListView 核心是重写BaseExpandableListAdpter,其实和之前写的普通的BaseAdapter是类似的, 但是BaseE ...

  6. android 仿qq修改头像,Qt:小项目仿QQ修改头像界面,技术点记录

    最近写了一个修改头像功能的UI,布局参考了QQ目前的修改头像界面.如下图 这里主要说明一下两个地方的技术:1.头像图片上层的遮罩层,圆形外部为灰色,内部为全透明:2.上传图片宽高比例可以通过鼠标拖拽移 ...

  7. Android仿QQ实现聊天功能

    前段时间下载了Android仿QQ界面和聊天的Demo,发现很有意思,于是研究了一下并自己在此基础上集成环信实现了在线聊天功能,可以实现注册.加人.审核通知.推送.创建群组.群组聊天,并加入了炫酷的背 ...

  8. Android仿QQ侧滑菜单

    先上效果图: GIF图有点模糊,源码已上传Github:Android仿QQ侧滑菜单 ####整体思路: 自定义ItemView的根布局(SwipeMenuLayout extends LinearL ...

  9. android支付宝支付微信支付封装,Android仿支付宝微信支付密码界面弹窗封装dialog...

    一,功能效果 二,实现过程 1,先写xml文件:dialog_keyboard.xml 注意事项 (1),密码部分用的是一个线性布局中6个TextView,并设置android:inputType=& ...

最新文章

  1. flutter 刷脸_GitHub - nnnggel/baidu_face_plugin: 百度人脸识别和活体检测 Flutter 插件(目前版本仅支持 Android)...
  2. 老李案例分享:Weblogic性能优化案例
  3. 原创:centos7.1下 ZooKeeper 集群安装配置+Python实战范例
  4. MySQL中文全文检索
  5. java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
  6. 面试官:说说Java中java.lang.Void和void有什么作用和区别?
  7. javascript --- [虚拟DOM] 初始化 实现
  8. 代码优化导致的奇葩问题
  9. tablednd保存 php,JQuery-tableDnD 拖拽的基本使用介绍
  10. 资深程序员的书单 - 转载自@Axb
  11. 在Android上实现汉字笔顺动画效果
  12. matlab程序产生OAM波,一种反射型极化转换超表面的轨道角动量产生结构设计的制作方法...
  13. 富士通Fujitsu DPK2181H Pro 打印机驱动
  14. PostgreSQL遍历Json
  15. win11安装texlive 2021版本
  16. 萤石云开放平台java_萤石云控制代码
  17. 背包问题(动态规划 C/C++)
  18. K-means算法的Java实现 聚类分析681个三国武将(1)
  19. 功夫茶篇∞潮州工夫茶:通古今之变
  20. Postman教程-Pre-request Script和Tests脚本进阶

热门文章

  1. 简历:如何挑选合适的简历模板
  2. 6.S081 lab6 cow
  3. 微软云 azure 数据迁移之oracle11g dataguard
  4. 【3D detection】CT3D部分代码的理解
  5. qq魔法表情原理,解密及其他
  6. winform连接blynk 控制开发板
  7. 营销活动该怎么来评估?赶快来学一下
  8. C++ boost库介绍以及开发环境搭建
  9. 第三部分第二节课全部
  10. 深度学习模型部署之模型优化