热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

版权声明:本文为博主原创文章,转载请注明出处.一、介绍这是新浪微博的一个帖子,刚好包括了话题、表情、@好友三种显示。显示方法上篇已经阐述了,就是使用SpannableString。这篇主要介绍显示这种

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

一、介绍

这是新浪微博的一个帖子,刚好包括了话题、表情、@好友三种显示。显示方法上篇已经阐述了,就是使用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()

               continue;

           }

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

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

           //设置前景色span

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

           if (end

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

               dealPattern(color,spannableString, patten, end);

           }

           break;

       }

   }

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

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

   public interface SpanClickListener{

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

               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

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

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

               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

                   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 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() {

               @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 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() {

               @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

 


推荐阅读
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
author-avatar
敦恒
招聘!招聘!招聘! 联系方式:56226135/shiziqian@hy9z.com 请优先邮件联系~谢谢!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有