仿微信、QQ的@功能

仿微信、QQ的@功能

前言:前一段时间,公司有一个项目需要加入@功能,我当时也没有啥思路,然后去网上看看有没有前人写过类似的文章或者代码。然后我在这里http://download.csdn.net/detail/u011818090/8534377找到了别人写的仿微博的@功能,感觉还可以,但是和我的需求不一样,所以就自己根据需求改编了他的代码。下面就讲讲我的@功能。
首先是需求:公司项目需求的中心思想是,你在群组聊天时,@群组中的某一个人,这个人接受到@信息,会在会话列表有标红提示,其他人接收到信息就是一个普通消息。我的当时遇到的问题就是这个,该如何让被@的人接收到信息有标红提醒。还有就是有一个非常让人难受的数据文档(格式如下所示)当时有两个方案:第一,根据名字来标记;第二,根据名字和用户Id来标记。然后再分析下:第一个方案,名字没有唯一性。所以第一个方案被排除了(排除过程很痛苦,其中经历了很多艰难的想法和尝试,就是因为这个奇葩的文档数据格式);然后是第二个方案,id有唯一性并且还可以将文档中的id填上,也可以判断content字段里面的内容是@信息还是一个普通的@文本信息。但是如何实现呢?
这是发送@信息的json串
大家都用过微信表情吧,他内部其实是一个表情对应一个特定的字符串,我就想,为什么这个不可以呢,一个名字里面包含了名字和Id。主要思路是运用正则的方式用一张图片去替代特定格式的字符串。下面上代码。

 //设置@图片和文字混搭
    public static CharSequence getExpressionString(Context context, String srcText,DynamicDrawableSpan drawableSpan){
        SpannableStringBuilder builder = new SpannableStringBuilder();
        builder.append(srcText);  //srcText是拼接好的字符串
        String text = builder.toString();
        Pattern pattern = Pattern.compile("\\[2f(.*?)\\]"); //这是一个约定好的正则字符串
        Matcher matcher = pattern.matcher(text);
        String atStr,atIndex;
        SpannableString spannable;

        int index = 0;
        while(matcher.find()){
            atIndex = matcher.group(1);//找到正则表达式中的括号()内匹配的字符串
            atStr = "[2f" + atIndex + "]";
            index = matcher.start(1) - 3; //得到括号内匹配的起始坐标
            spannable = new SpannableString(atStr);
            spannable.setSpan(drawableSpan, 0, spannable.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
            builder.replace(index, index + atStr.length(), spannable);
        }
        return builder;
    }

上面的方法是将一个原始的拼接成特定字符串的drawableSpan进行正则替换成一个名字图片。
下面是将name和Id拼成特定字符创的代码

/**
     * 拼接@和姓名
     * @param userName
     * @param userId
     */
    private void spilecName(String userName, String userId) {

        int currentIndex = editText.getSelectionStart();  //获得光标的起始位置
        String nameStr = "[2f" + userName + "/" + userId + "]";
        //通过输入的@符号进入好友列表并返回@的人,删除之前的@
        editText.getText().replace(currentIndex - 1,currentIndex,"");

        setAtImageSpan(nameStr,userName);
    }

可以看到我将name和Id拼接成String nameStr = "[2f" + userName + "/" + userId + "]"; 这种形式,然后用Pattern pattern = Pattern.compile("\\[2f(.*?)\\]")进行正则表达式匹配。下面是将文字信息转成图片信息

/**
     * 将@的信息转化成图片
     * @param nameStr
     * @param name
     */
    private void setAtImageSpan(String nameStr, String name) {
        Editable eidit_text = editText.getEditableText();
        if (null != name){
            String name1 = "@" + name + " ";  //后面加一个空格为了与之后拼接的文字隔开
            if (null != name1 && name1.trim().length() > 0){
                final Bitmap bmp = getNameBitmap(name1);

                DynamicDrawableSpan drawableSpan = new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) {
                    @Override
                    public Drawable getDrawable() {
                        BitmapDrawable drawable = new BitmapDrawable(getResources(),bmp);
                        drawable.setBounds(0,0,
                                            bmp.getWidth(),
                                            bmp.getHeight());
                        return drawable;
                    }
                };

                CharSequence cs = getExpressionString(AtActivity.this, nameStr, drawableSpan);
                builder = new SpannableStringBuilder(cs);

                //获取光标所在位置
                currentIndex = editText.getSelectionStart();
                builder.setSpan(builder,0, builder.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        if (currentIndex < 0 || currentIndex >= eidit_text.length()) {
            eidit_text.append(builder);
        } else {
            eidit_text.insert(currentIndex, builder);
        }
    }

    /**
     * 将文字转成图片
     * @param name
     * @return
     */
    private Bitmap getNameBitmap(String name) {
        Paint paint = new Paint();
        paint.setColor(getResources().getColor(R.color.black));
        paint.setAntiAlias(true);
        paint.setTextSize(DensityUtils.dp2px(AtActivity.this,18));
        Rect rect = new Rect();
        paint.getTextBounds(name,0,name.length(),rect);

        //获得字符串在屏幕上的长度
        int width = (int) (paint.measureText(name));
        final Bitmap bmp = Bitmap.createBitmap(width,rect.height() + 8, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bmp);
        Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();

        //(行高-字体高度)/2+字体高度-6
        float fontTotalHeight = fontMetrics.bottom - fontMetrics.top;
        //  canvas.drawText(name, rect.left, rect.height() - rect.bottom, paint);
        float offY = fontTotalHeight / 2;

        float newY = rect.height() / 2 + offY;
        canvas.drawText(name, rect.left, newY - 4, paint);
        return bmp;
    }

通过以上的处理,就能够将name和Id信息存进一张@的图片中了。接收方通过解析@信息的内容,判断该内容中是否有自己的Id,然后系统再进行相应的处理。

大致的思路就写完了,一些简单的逻辑,大家可以看我上面给的链接的代码。或者看我下面的附上的整个代码。我的代码中还加入了群员名字的搜索功能,搜索的关键字标红处理。附上代码如下:

说明:代码只是简单的写了发送方的@功能信息,并没有实际的聊天功能(聊天比较复杂)。如果各位有做即时聊天的需要@功能的,希望我这个思路能对大家有所帮助。
AtActivity代码:

package com.example.hhly_pc.enumuse;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.graphics.BitmapCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.DynamicDrawableSpan;
import android.widget.EditText;
import android.w
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值