android 微博字体高亮,安卓开发札记——高仿新浪微博文字处理(实现关键字高亮,自定义表情替换并加入点击事件实现)...

安卓开发笔记——高仿新浪微博文字处理(实现关键字高亮,自定义表情替换并加入点击事件实现)

先让大家看下效果图,这个是我自己在闲暇时间仿写的新浪微博客户端:

07322026.gif

07322027.jpg  

07322028.jpg

今天来讲讲如何实现上图的效果,这里需要用到SpannableString这个工具类,如果你对这个类并不熟悉,可以先看下我之前写的2篇文章:

先来说下关于新浪微博消息的结构,在获取新浪微博消息的时候,我们会发现这几个东西:

话题:以##为收尾,例如#世界读书日#等。

At:以@开头,空格结尾,例如@新浪微博 等。

网址:以http://开头,例如http://www.baidu.com/。

表情:以[]为收尾,例如[微笑]、[哈哈]等。

在一段140字的文本中要找出上面这些关键字,无疑就是用到正则表达式了,在这里我定义了4个正则表达式:

//定义正则表达式

private static final String AT = "@[\u4e00-\u9fa5\\w]+";//@人

private static final String TOPIC = "#[\u4e00-\u9fa5\\w]+#";//##话题

private static final String EMOJI = "\\[[\u4e00-\u9fa5\\w]+\\]";//表情

private static final String URL = "http://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";//url

然后根据我上2篇文章提供的正则匹配法去匹配微博消息的文本字段,在这里有些技巧和大家分享下:

最早我在实现这个功能的时候用很多个while循环,先匹配@,再匹配话题,再匹配表情最后匹配Url,这样子在实现层面上固然没什么问题,但是我们写程序还是需要注意代码的运行效率的,这里给大家分享些技巧:

1、我们可以先把我们想匹配的正则拼接起来用"|"分割开,然后把每一部分的正则用小括号关联起来,然后可以在group方法里设置索引来定位匹配到正则内容,索引0代表全部,1代表第一个括号,以此类推。

2、关于ClickableSpan实现可以点击样式,这里我们需要做2个处理

(1)、在ClickableSpan的源码里我们可以发现这样的2句话(如下图),它是带有自定颜色和文字下划线的

07322029.png

所以这里我们需要对它做下处理,我们去继承这个类然后复写它的方法,定义我们自己想要的颜色和样式就可以了。

1 /**

2 * 继承ClickableSpan复写updateDrawState方法,自定义所需样式3 *@authorRabbit_Lee4 *5 */

6 public static class MyClickableSpan extendsClickableSpan {7

8 @Override9 public voidonClick(View widget) {10

11 }12

13 @Override14 public voidupdateDrawState(TextPaint ds) {15 super.updateDrawState(ds);16 ds.setColor(Color.BLUE);17 ds.setUnderlineText(false);18 }19

20 }

(2)、由于@昵称、#话题#、http://等这些关键字是可以点击的,所以我们需要对TextView做一些处理,需要去设置它的MovementMethod,具体看下面代码。

3、在匹配表情(下文会提到),这里需要注意的一个地方是当我们获取到了Bitmap对象的时候需要对这个对象进行压缩处理,要使得它的尺寸大小和我们的TextView的字体大小一致。

1 /**

2 * 设置微博内容样式3 *@paramcontext4 *@paramsource5 *@paramtextView6 *@return

7 */

8 public static SpannableString getWeiBoContent(finalContext context, String source, TextView textView) {9 SpannableString spannableString = newSpannableString(source);10

11 //设置正则

12 Pattern pattern =Pattern.compile(REGEX);13 Matcher matcher =pattern.matcher(spannableString);14

15 if(matcher.find()) {16 //要实现文字的点击效果,这里需要做特殊处理

17 textView.setMovementMethod(LinkMovementMethod.getInstance());18 //重置正则位置

19 matcher.reset();20 }21

22 while(matcher.find()) {23 //根据group的括号索引,可得出具体匹配哪个正则(0代表全部,1代表第一个括号)

24 final String at = matcher.group(1);25 final String topic = matcher.group(2);26 String emoji = matcher.group(3);27 final String url = matcher.group(4);28

29 //处理@符号

30 if (at != null) {31 //获取匹配位置

32 int start = matcher.start(1);33 int end = start +at.length();34 MyClickableSpan clickableSpan = newMyClickableSpan() {35

36 @Override37 public voidonClick(View widget) {38 //这里需要做跳转用户的实现,先用一个Toast代替

39 Toast.makeText(context, "点击了用户:" +at, Toast.LENGTH_LONG).show();40 }41 };42 spannableString.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);43 }44

45 //处理话题##符号

46 if (topic != null) {47 int start = matcher.start(2);48 int end = start +topic.length();49 MyClickableSpan clickableSpan = newMyClickableSpan() {50

51 @Override52 public voidonClick(View widget) {53 Toast.makeText(context, "点击了话题:" +topic, Toast.LENGTH_LONG).show();54 }55 };56 spannableString.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);57 }58

59 if (emoji != null) {60 int start = matcher.start(3);61 int end = start +emoji.length();62 int ResId =EmotionUtils.getImgByName(emoji);63 Bitmap bitmap =BitmapFactory.decodeResource(context.getResources(), ResId);64 if (bitmap != null) {65 //获取字符的大小

66 int size = (int) textView.getTextSize();67 //压缩Bitmap

68 bitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);69 //设置表情

70 ImageSpan imageSpan = newImageSpan(context, bitmap);71 spannableString.setSpan(imageSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);72 }73 }74

75 //处理url地址

76 if (url != null) {77 int start = matcher.start(4);78 int end = start +url.length();79 MyClickableSpan clickableSpan = newMyClickableSpan() {80

81 @Override82 public voidonClick(View widget) {83 Toast.makeText(context, "点击了网址:" +url, Toast.LENGTH_LONG).show();84 }85 };86 spannableString.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);87 }88 }89

90 returnspannableString;91 }

再来说下关于表情替换的实现,首先我们需要把表情我们需要的表情下载下来存在我们的资源文件中,由于微博信息返回的是[XX],这里的XX是中文而我们的资源文件的命名不可以是中文,所以我们这边可以写一个资源存储类,用一个静态的Map集合去封装,把中文当成Key去对应Int类型的资源ID。

1 packagecom.lcw.weibo.utils;2

3 importjava.io.Serializable;4 importjava.util.HashMap;5 importjava.util.Map;6

7 importcom.lcw.weibo.R;8

9 @SuppressWarnings("serial")10 public class EmotionUtils implementsSerializable {11

12 public static MapemojiMap;13

14 static{15 emojiMap = new HashMap();16 emojiMap.put("[微笑]", R.drawable.d_hehe);17 emojiMap.put("[呵呵]", R.drawable.d_hehe);18 emojiMap.put("[嘻嘻]", R.drawable.d_xixi);19 emojiMap.put("[哈哈]", R.drawable.d_haha);20 emojiMap.put("[爱你]", R.drawable.d_aini);21 emojiMap.put("[挖鼻屎]", R.drawable.d_wabishi);22 emojiMap.put("[吃惊]", R.drawable.d_chijing);23 emojiMap.put("[晕]", R.drawable.d_yun);24 emojiMap.put("[泪]", R.drawable.d_lei);25 emojiMap.put("[馋嘴]", R.drawable.d_chanzui);26 emojiMap.put("[抓狂]", R.drawable.d_zhuakuang);27 emojiMap.put("[哼]", R.drawable.d_heng);28 emojiMap.put("[可爱]", R.drawable.d_keai);29 emojiMap.put("[怒]", R.drawable.d_nu);30 emojiMap.put("[汗]", R.drawable.d_han);31 emojiMap.put("[害羞]", R.drawable.d_haixiu);32 emojiMap.put("[心]", R.drawable.emoji_0x2764);33 emojiMap.put("[睡觉]", R.drawable.d_shuijiao);34 emojiMap.put("[钱]", R.drawable.d_qian);35 emojiMap.put("[偷笑]", R.drawable.d_touxiao);36 emojiMap.put("[笑cry]", R.drawable.d_xiaoku);37 emojiMap.put("[doge]", R.drawable.d_doge);38 emojiMap.put("[喵喵]", R.drawable.d_miao);39 emojiMap.put("[酷]", R.drawable.d_ku);40 emojiMap.put("[衰]", R.drawable.d_shuai);41 emojiMap.put("[闭嘴]", R.drawable.d_bizui);42 emojiMap.put("[鄙视]", R.drawable.d_bishi);43 emojiMap.put("[花心]", R.drawable.d_huaxin);44 emojiMap.put("[鼓掌]", R.drawable.d_guzhang);45 emojiMap.put("[悲伤]", R.drawable.d_beishang);46 emojiMap.put("[思考]", R.drawable.d_sikao);47 emojiMap.put("[生病]", R.drawable.d_shengbing);48 emojiMap.put("[亲亲]", R.drawable.d_qinqin);49 emojiMap.put("[怒骂]", R.drawable.d_numa);50 emojiMap.put("[太开心]", R.drawable.d_taikaixin);51 emojiMap.put("[懒得理你]", R.drawable.d_landelini);52 emojiMap.put("[右哼哼]", R.drawable.d_youhengheng);53 emojiMap.put("[左哼哼]", R.drawable.d_zuohengheng);54 emojiMap.put("[嘘]", R.drawable.d_xu);55 emojiMap.put("[委屈]", R.drawable.d_weiqu);56 emojiMap.put("[吐]", R.drawable.d_tu);57 emojiMap.put("[可怜]", R.drawable.d_kelian);58 emojiMap.put("[打哈气]", R.drawable.d_dahaqi);59 emojiMap.put("[挤眼]", R.drawable.d_jiyan);60 emojiMap.put("[失望]", R.drawable.d_shiwang);61 emojiMap.put("[顶]", R.drawable.d_ding);62 emojiMap.put("[疑问]", R.drawable.d_yiwen);63 emojiMap.put("[困]", R.drawable.d_kun);64 emojiMap.put("[感冒]", R.drawable.d_ganmao);65 emojiMap.put("[拜拜]", R.drawable.d_baibai);66 emojiMap.put("[黑线]", R.drawable.d_heixian);67 emojiMap.put("[阴险]", R.drawable.d_yinxian);68 emojiMap.put("[打脸]", R.drawable.d_dalian);69 emojiMap.put("[傻眼]", R.drawable.d_shayan);70 emojiMap.put("[猪头]", R.drawable.d_zhutou);71 emojiMap.put("[熊猫]", R.drawable.d_xiongmao);72 emojiMap.put("[兔子]", R.drawable.d_tuzi);73 }74

75 public static intgetImgByName(String imgName) {76 Integer integer =emojiMap.get(imgName);77 return integer == null ? -1: integer;78 }79 }

好了,到这里文章就结束了,有任何疑问或者建议,大家可以在文章评论给我留言。

作者:李晨玮

出处:http://www.cnblogs.com/lichenwei/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之气,日后必有一番作为!旁边有“推荐”二字,你就顺手把它点了吧,相得准,我分文不收;相不准,你也好回来找我!

1楼superstar求源码Re: 李晨玮@superstar,整个项目的源码不好给,实现微博文字处理的效果代码都贴上去了,直接复制就可以用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值