欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿新浪微博、QQ空间等帖子显示(2)

程序员文章站 2024-03-05 17:18:19
一、介绍 这是新浪微博的一个帖子,刚好包括了话题、表情、@好友三种显示。显示方法上篇已经阐述了,就是使用spannablestring。这篇主要介绍显示这种帖子的解析...

一、介绍

Android仿新浪微博、QQ空间等帖子显示(2)

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

二、实现

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

话题用##号括起来
表情用[]表示
@好友昵称
借助正则匹配来解析帖子信息。

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

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

private static void dealpattern(int color, spannablestring spannablestring, pattern patten, int start) 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(new foregroundcolorspan(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 void dealclick(spannablestring spannablestring, pattern patten, int start, final spanclicklistener 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(new clickablespan() {
    @override
    public void onclick(view widget) {
     spanclicklistener.onspanclick(bean);
    }
    @override
    public void updatedrawstate(textpaint ds) {
     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(context context,
   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 = new imagespan(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 static spannablestring getkeywordspan(int color, string str, string patterstr) throws exception {
  spannablestring spannablestring = new spannablestring(str);
  pattern patten = pattern.compile(patterstr, pattern.case_insensitive);
  dealpattern(color, spannablestring, patten, 0);
  return spannablestring;
 }

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

 public static spannablestring gettopicspan(int color, string str, boolean clickable,spanclicklistener spanclicklistener, topic topic) throws exception {
  spannablestring spannablestring = new spannablestring(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 static spannablestring getatuserspan(int color, string str, boolean clickable, spanclicklistener spanclicklistener, list<user> atusers) throws exception {
  spannablestring spannablestring = new spannablestring(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(context context, string str) throws exception {
  return expressionconvertutil.getinstace().getexpressionstring(context, str);
 }

三、使用

1.关键字变色

private void testcoloredkeywd() {
  string string = "android一词的本义指“机器人”,同时也是google于2007年11月5日,android logo相关图片,android logo相关图片(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, new spanutils.spanclicklistener<topic>() {
    @override
    public void onspanclick(topic t) {
     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 = new arraylist<>();
  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, new spanutils.spanclicklistener<user>() {
    @override
    public void onspanclick(user user) {
     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);
 }

效果图

Android仿新浪微博、QQ空间等帖子显示(2)

下载:https://github.com/linechen/spannablestringdemo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。