类似新浪微博帖子显示话题、@好友、表情解析等

版权声明:本文为博主原创文章,转载请注明出处.

一、介绍

这是新浪微博的一个帖子,刚好包括了话题、表情、@好友三种显示。显示方法上篇已经阐述了,就是使用SpannableString。这篇主要介绍显示这种帖子的解析工具类。

二、实现

1.字符串表示和对应正则表达式

  • 话题用##号括起来
  • 表情用[]表示
  • @好友昵称

借助正则匹配来解析帖子信息。

  • 话题 -> #[^#]+#
  • 表情 -> [[^]]+]
  • @好友 -> @好友昵称

2.写一个通用方法,对spanableString进行正则判断,如果符合要求,则将内容变色

private static voiddealPattern(int color, SpannableString spannableString, Pattern patten, intstart) throws Exception {

       Matcher matcher =patten.matcher(spannableString);

       while (matcher.find()) {

           String key = matcher.group();

           //返回第一个字符的索引的文本匹配整个正则表达式,ture则继续递归

           if (matcher.start() < start) {

               continue;

           }

           //计算该内容的长度,也就是要替换的字符串的长度

           int end = matcher.start() +key.length();

           //设置前景色span

           spannableString.setSpan(newForegroundColorSpan(color), matcher.start(), end,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

           if (end <spannableString.length()) {

               //如果整个字符串还未验证完,则继续。。

               dealPattern(color,spannableString, patten, end);

           }

           break;

       }

   }

3.因为有些是可点击的,所以需要一个方法来处理可点击的内容

先定义一个接口,通过接口的方式将点击事件交给调用者

   public interface SpanClickListener<T>{

       void onSpanClick(T t);

   }

写一个通用方法,对spanableString进行正则判断,如果符合要求,将内容设置可点击

private static voiddealClick(SpannableString spannableString, Pattern patten, int start, finalSpanClickListener spanClickListener, final Object bean){

       Matcher matcher =patten.matcher(spannableString);

       while (matcher.find()) {

           String key = matcher.group();

           //返回第一个字符的索引的文本匹配整个正则表达式,ture则继续递归

           if (matcher.start() < start) {

               continue;

           }

           //计算该内容的长度,也就是要替换的字符串的长度

           int end = matcher.start() +key.length();

           spannableString.setSpan(newClickableSpan() {

               @Override

               public void onClick(Viewwidget) {

                   spanClickListener.onSpanClick(bean);

               }

               @Override

               public void updateDrawState(TextPaintds) {

                   super.updateDrawState(ds);

                   //设置画笔属性

                   ds.setUnderlineText(false);//默认有下划线

               }

           }, matcher.start(), end,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

           if (end <spannableString.length()) {

               //如果整个字符串还未验证完,则继续。。

               dealClick(spannableString,patten, end, spanClickListener, bean);

           }

           break;

       }

   }

4.表情解析方法(后面会写一篇关于表情的处理)

 

private void dealExpression(Contextcontext,

           SpannableString spannableString,Pattern patten, int start)

           throws Exception {

       Matcher matcher =patten.matcher(spannableString);

       while (matcher.find()) {

 

           String key = matcher.group();

           if (matcher.start() < start) {

               continue;

           }

           String value = emojiMap.get(key);

           if (TextUtils.isEmpty(value)) {

               continue;

           }

           //通过上面匹配得到的字符串来生成图片资源id

           int resId =context.getResources().getIdentifier(value, "drawable",

                   context.getPackageName());

           if (resId != 0) {

               Drawable emoji =context.getResources().getDrawable(resId);

               int w = (int)(emoji.getIntrinsicWidth() * 0.40);

               int h = (int)(emoji.getIntrinsicHeight() * 0.40);

               emoji.setBounds(0, 0, w, h);

               //通过图片资源id来得到bitmap,用一个ImageSpan来包装

               ImageSpan imageSpan = newImageSpan(emoji);

               //计算该图片名字的长度,也就是要替换的字符串的长度

               int end = matcher.start() +key.length();

               //将该图片替换字符串中规定的位置中

               spannableString.setSpan(imageSpan, matcher.start(), end,

                       Spannable.SPAN_INCLUSIVE_EXCLUSIVE);

               if (end <spannableString.length()) {

                   dealExpression(context,spannableString, patten, end);

               }

               break;

           }

       }

   }

5.关键词变色处理方法,这个实际中的使用场景比如地图关键字搜索,匹配到关键字的地址中关键字显示特别颜色

 

public staticSpannableString getKeyWordSpan(int color, String str, String patterStr) throwsException {

       SpannableString spannableString = newSpannableString(str);

       Pattern patten =Pattern.compile(patterStr, Pattern.CASE_INSENSITIVE);

       dealPattern(color, spannableString,patten, 0);

       returnspannableString;

   }

6.话题处理,参数中需要传入话题对象。这里只处理了一个帖子中只有一个话题的情况

   public static SpannableString getTopicSpan(intcolor, String str, boolean clickable,SpanClickListener spanClickListener, Topictopic) throws Exception {

       SpannableString spannableString = newSpannableString(str);

       Pattern patten =Pattern.compile(PatternString.TOPIC_PATTERN, Pattern.CASE_INSENSITIVE);

       if(clickable){

           dealClick(spannableString, patten, 0,spanClickListener, topic);

       }

       dealPattern(color, spannableString,patten, 0);

       return spannableString;

   }

7.@好友处理,参数中需要传入@的好友列表

 

public staticSpannableString getAtUserSpan(int color, String str, boolean clickable,SpanClickListener spanClickListener, List<User> atUsers) throws Exception{

       SpannableString spannableString = newSpannableString(str);

       Pattern patten;

       for (User u : atUsers) {

           patten = Pattern.compile("@"+ u.getName(), Pattern.CASE_INSENSITIVE);

           if(clickable){

               dealClick(spannableString,patten, 0, spanClickListener, u);

           }

           dealPattern(color, spannableString,patten, 0);

       }

       return spannableString;

   }

8.表情处理,就这么简洁

   public static SpannableString getExpressionSpan(Contextcontext, String str) throws Exception {

       returnExpressionConvertUtil.getInstace().getExpressionString(context, str);

   }

 三、使用

1.关键字变色

private void testColoredKeywd(){

       String string = "Android一词的本义指机器人,同时也是Google2007115,Android logo相关图片,Androidlogo相关图片(36)\n";

       SpannableString cardText = null;

       try {

           cardText =SpanUtils.getKeyWordSpan(getResources().getColor(R.color.md_green_600), string,"Android");

       } catch (Exception e) {

           e.printStackTrace();

       }

       tvColoredKeywd.setText(cardText);

   }

2.话题测试,需要注意的是,让部分内容可点击需要设置tvTopic.setMovementMethod(LinkMovementMethod.getInstance());,否则点击无效果

private void testTopic(){

       String topic = "#舌尖上的大连#四种金牌烤芝士吃法爱吃芝士的盆友不要错过了~L秒拍视频\n";

       SpannableString topicText = null;

       try {

           topicText =SpanUtils.getTopicSpan(Color.BLUE, topic, true, newSpanUtils.SpanClickListener<Topic>() {

               @Override

               public void onSpanClick(Topict) {

                   Toast.makeText(MainActivity.this,"点击话题:" +t.toString() , Toast.LENGTH_SHORT).show();

               }

           }, new Topic(1, "舌尖上的大连"));

       } catch (Exception e) {

           e.printStackTrace();

       }

       tvTopic.setText(topicText);

       //如果想实现点击,必须要设置这个

       tvTopic.setMovementMethod(LinkMovementMethod.getInstance());

   }

3.@好友测试

 

private void textAtUsers(){

       List<User> users = newArrayList<>();

       users.add(new User(1, "好友1"));

       users.add(new User(2, "好友2"));

       StringBuilder sb = new StringBuilder("快来看看啊");

       for (User u : users) {

           sb.append("@").append(u.getName());

       }

       sb.append("\n");

       try {

           SpannableString atSpan =SpanUtils.getAtUserSpan(Color.BLUE, sb.toString(), true, newSpanUtils.SpanClickListener<User>() {

               @Override

               public void onSpanClick(Useruser) {

                   Toast.makeText(MainActivity.this, "@好友:" + user.toString(), Toast.LENGTH_SHORT).show();

               }

           }, users);

 

           tvTestAt.setText(atSpan);

           tvTestAt.setMovementMethod(LinkMovementMethod.getInstance());

       } catch (Exception e) {

           e.printStackTrace();

       }

   }

4.表情测试

 private void textExpression(){

       String exStr = "今天天气很好啊[呲牙],是不是应该做点什么[]";

       SpannableString span = null;

       try {

           span = SpanUtils.getExpressionSpan(this,exStr);

       } catch (Exception e) {

           e.printStackTrace();

       }

       tvExpression.setText(span);

   }

效果图

下载:https://github.com/LineChen/SpannableStringDemo

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值