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);
 }

效果图

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

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

(0)

相关推荐

  • Android仿新浪微博/QQ空间滑动自动播放视频功能

    先来看看效果图 关键代码 1.监听滚动事件 首先要给listview添加setOnScrollListener监听,注意这个监听在recyclerView上是addOnScrollListener,也就是说下面代码同时支持recyclerView. public int firstVisible=0,visibleCount=0, totalCount=0; videoList.setOnScrollListener(new AbsListView.OnScrollListener() { @O

  • Android仿新浪微博个人信息界面及其他效果

    本教程为大家分享了Android微博个人信息界面设计代码,供大家参考,具体内容如下 根据用户ID获取用户信息接口: http://open.weibo.com/wiki/2/users/show 如果你已经实现前面的功能那个这个人信息界面便是小菜一碟,此处不作叙述. 补充 1.时间处理类: 处理微博发出时间距现在时刻的时间.应该是比较容易理解的. /** * 时间处理类 */ public class DateUtils { public String getInterval(String cr

  • Android仿新浪微博分页管理界面(3)

    本文实例为大家分享了Android仿新浪微博分页管理界面的具体代码,供大家参考,具体内容如下 多个activity分页管理,为了方便获取上下文,采用继承TabActivity的传统方法. 大致思路:使用RadioGroup点击触发不同的选卡项,选卡项绑定不同的activiity,进而进行分页管理.详解见注解. /** * 主Activity * 通过点击RadioGroup下的RadioButton来切换不同界面 * Created by D&LL on 2016/7/20. */ public

  • Android仿新浪微博自定义ListView下拉刷新(4)

    自定义PullToRefreshListView继承ListView,在ListView头部添加一个下拉的头部布局.跟ListView用法完全一致. 该自定义Listview代码详解具体可参考: http://www.jb51.net/article/97845.htm 此处详细介绍Adapter的详细代码. 1.首先给Adapter绑定ListView布局. 2.其次创建一个层次对应组件的类,将对应的组件和对象进行关联,提高效率. 3.然后跟陆获得的图片路径异步下载图片,由于不知道该微博图片的

  • Android集成新浪微博第三方登录的方法

    本文实例讲述了Android集成新浪微博第三方登录的方法.分享给大家供大家参考.具体实现方法如下: 1.下载微博的sdk ,导入微博的jar包两个 android-support-v4.jar和weibosdkcore.jar两个包 2.把新浪微博中的demo_src中SDK中的com,导入到项目中 3.用demo中的constants,主要是参数设置,将里面的参数改成自己的参数. 4.编写代码,主要步骤如下: 复制代码 代码如下: // 初始化微博对象 mWeiboAuth = new Wei

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

    TextView通常用来显示普通文本,但是有时候需要对其中某些文本进行样式.事件方面的设置.Android系统通过SpannableString类来对指定文本进行相关处理,实际应用中用的比较多的地方比如聊天时显示表情啊,朋友圈或社区中话题的显示.@好友显示和点击等等,关键字显示不同颜色-- 1.BackgroundColorSpan 背景色 SpannableString spanText = new SpannableString("BackgroundColorSpan"); sp

  • Android仿新浪微博发布微博界面设计(5)

    本教程为大家分享了Android发布微博.添加表情等功能的具体代码,供大家参考,具体内容如下 发布一条新微博接口:http://open.weibo.com/wiki/2/statuses/update 上传图片并发布一条新微博接口:http://open.weibo.com/wiki/2/statuses/upload 1.根据有没有图片来选择相应的接口. 2.根据输入框的改变判断文字数. 3.创建一个girlview显示发送的图片,最最多9张,此处由于请求参数的的原因,最多上传一张图片,选择

  • Android仿新浪微博启动界面或登陆界面(1)

    本文为大家分享了Android模仿新浪微博启动界面&登陆界面的具体实现代码,供大家参考,具体内容如下 启动界面 主要有两个功能: 1.加载启动动画 2.判断网络,有者直接进入登陆界面,否则去设置网络 代码较简单,主要采用AlphaAnimation()方法和动画监听器,使一张图片产生渐变动画.在动画启动的时候判断网络,动画结束时完成判断并进入登陆界面. /** * Created by D&LL on 2016/5/25. * 初始页面加载界面 */ public class Splash

  • Android用PopupWindow实现新浪微博的分组信息实例

    最近看到新浪微博顶部栏的微博分组效果很炫,从网上查了一些资料明白原来是用PopupWindow实现的,今天自己也写了一个例子实现了这种效果,希望对大家有帮助. PopupWindow就是弹出窗口的意思,类似windows下面的开始按钮.PopupWindow可以实现浮层效果,而且可以自定义显示位置,出现和退出时的动画. 效果如下: 实现思路: 在一个PopupWindow里放一个ListView,从而来达到分组信息的实现! 具体主要实现代码: group_list.xml: <?xml vers

  • Android仿新浪微博oauth2.0授权界面实现代码(2)

    oauth2.0授权界面,大致流程图: 前提准备: 在新浪开放平台申请appkey和appsecret:http://open.weibo.com/. 熟悉oauth2.0协议,相关知识:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html OAuth2的access_token接口:http://open.weibo.com/wiki/OAuth2/access_token 代码详解 大致思路如下:建立一个webview加载授权界面,授权回

随机推荐