概述

1.原理和实现思路

2.表情图片显示

3.表情面板

4.表情的输入框插入和删除

5.表情添加脚本

Android中表情功能,一般都不是用ImageView去设置图片实现的,
表情一般会嵌套在文本之中,那么如何实现呢,这里就介绍一下其中的原理,此外还有相关功能的实现思路和具体代码

先看下良心动态图~

------------------------------------------------------------------------------

1.原理和思路

a.表情内容的数据格式
表情看上去是图片,但是在数据传输的时候本质上是一个特殊文本
比如QQ表情就是一个 "/表情字母"的结构,比如害羞的表情就是/hx,呲牙就是/cy...
微博里表情就是"[表情名字]"的接口,比如可爱的表情就是[可爱]等等...

b.特殊文本显示图片的原理
需要用到安卓中的SpannableString拓展性字符串相关知识
SpannableString可以让一段字符串在显示的时候,将其中某小段文字附着上其他内容,
附着的拓展内容可能是图片,或者是文字格式,比如加粗斜体等

下面稍微展开介绍下SpannableString,会的可以跳过

常用的拓展内容包含有
BackgroundColorSpan 背景色 
ClickableSpan 文本可点击,有点击事件
UnderlineSpan 下划线
ImageSpan 图片
StyleSpan 字体样式:粗体、斜体等
URLSpan 文本超链接
此外还有删除线,缩放大小等不同样式的拓展

用法

  1. SpannableString spannableString = new SpannableString(source);
  2. ImageSpan span = new ImageSpan(context, bitmap);
  3. spannableString.setSpan(span, start, start + emojiStr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );

复制代码

解释下用法
首先将原String文字包装成拓展性文字SpannableString

再创建一个需要类型的Span对象,比如表情图片就是ImageSpan,

然后利用SpannableString的setSpan方法,将span对象设置在对应位置,
start就是需要附着的内容的开始位置
end是需要附着的内容的开始位置
flag标志位,这里是最常用的EXCLUSIVE_EXCLUSIVE的表示span拓展文本不包含前后,
此外还有INCLUSIVE是包含的意思

举例说明下,原文字是"文章作者是大帅比"
那我创建个粗体拓展内容,并且要将其附着到作者二字上让其变成粗体,
那开始位置就是2,即第三个字;结束位置就是4,即第五个
然后按照"包头不包尾"原则,包含第三个字不包含第五个字,即处理的就是第三四俩字"作者"
flag我们将其设为EXCLUSIVE_INCLUSIVE即不包含前包含后

那最终显示的文字就是
"文章作者是大帅比"
如果我们在附着内容及作者二字前面输入内容时,由于是EXCLUSIVE不包含,所以不会跟着变化
"文章boredream作者是大帅比"
如果我们在附着内容及作者二字后面输入内容时,由于是INCLUSIVE包含,新内容也会包含进效果
"文章作者boredream是大帅比"

c.特殊文字的匹配
知道要处理哪些特殊文本,怎么处理,还有一步是怎么把特殊文本从一段文字里挑出来
即获取到特殊本文的开始和结束位置,以及他的文字内容
这里就要用到正则去进行匹配获取了正则的规则就不细说了,下面介绍下表情这里的正则匹配

------------------------------------------------------------------------------

2.表情图片显示

文字附着表情图片很简单,用SpannableString中的ImageSpan,
难点在于正则部分的获取处理

首先是正则的写法,根据需要自行编写规则
这里以微博表情为例
String regex = "\\[[\u4e00-\u9fa5\\w]+\\]";
简单介绍下

最外面是方括号符号,要注意由于[]在正则中有特殊意义,
所以需要用斜杠\转义一下(\本身也需要转义所以是俩\\)

中间\u4e00-\u9fa5表示中文,
\\w表示下划线的任意单词字符
+ 代表一个或者多个
那么这段正则就代表,匹配方括号内有一或多个文字和单词字符的文本

然后去while循环匹配就可以了
用matcher.find获取到匹配的开始位置,作为setSpan的start值,
用matcher.group方法获取到匹配规则的具体表情文字,
end值则直接利用开始位置加上表情文字的长度即可

贴上代码

  1. public static SpannableString getEmotionContent( final Context context, final TextView tv, String source) {
  2. SpannableString spannableString = new SpannableString(source);
  3. Resources res = context.getResources();
  4. String regexEmotion = "\\[([\u4e00-\u9fa5\\w])+\\]" ;
  5. Pattern patternEmotion = Pattern. compile(regexEmotion);
  6. Matcher matcherEmotion = patternEmotion.matcher(spannableString);
  7. while (matcherEmotion.find()) {
  8. // 获取匹配到的具体字符
  9. String key = matcherEmotion.group();
  10. // 匹配字符串的开始位置
  11. int start = matcherEmotion.start();
  12. // 利用表情名字获取到对应的图片
  13. Integer imgRes = EmotionUtils. getImgByName(key);
  14. if (imgRes != null) {
  15. // 压缩表情图片
  16. int size = ( int) tv.getTextSize();
  17. Bitmap bitmap = BitmapFactory.decodeResource(res, imgRes);
  18. Bitmap scaleBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
  19. ImageSpan span = new ImageSpan(context, scaleBitmap);
  20. spannableString.setSpan(span, start, start + key.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
  21. }
  22. }
  23. return spannableString;
  24. }

复制代码

基本思路前面提过了,图片处理的地方还要再说明下
表情如果直接获取资源文件里的图片,可能会过大,所以方法参数里传入了需要显示的文字控件,
然后利用文字大小去将表情图片再压缩一下

其中
EmotionUtils类就不介绍了,里面就是一个map集合,key为表情名字,value为表情图片的resId,
然后提供一个getImgByName的方法可以根据名字获取图片
键值对需要一个个添加比较麻烦,我们会在最后介绍一个表情添加的脚本,方便快速导入图片资源

------------------------------------------------------------------------------

3.表情面板

结构就是ViewPager提供多页滑动,每页都是一个GridView显示20个表情,末尾还有一个删除按钮
ViewPager和GridView的基本使用方法就不介绍了,这里说明下其中的特殊处理

a.每个GridView的大小设置
GridView会显示3行7列,共21个Item
为了让Item能大小合适,最好的方法是利用动态计算的方式设置宽高,因为屏幕宽度各有不同
其他的一些大小计算也要注意用dp值转换下获取对应的px再使用,保证适配问题

思路是
获取屏幕宽度,减去间隙距离,然后除以7算出每个Item需要的宽度,
然后再乘以3加上需要的间隙,算出表情面板的高度,利用算出来的值去创建设置面板大小

b.需要多少个GridView
一共有多少页呢,虽然表情大部分情况下总数是固定的,
但是最好还是根据代码的方式算出来需要多少页,而非直接人去目测计算要多少个GridView

思路是
for循环全部的图片名字,这里利用map.keySet获取全部的键集合
每次循环都把图片名添加到一个集合中,
然后进行判断,如果满20个了就作为一组表情,新建一个GridView设置上去
最后把所有表情生成的一个个GridView放到一个总view集合中,利用ViewPager显示

c.GridView末尾删除键处理
适配器和点击事件中,都利用position判断,如果是最后一个就进行特殊的显示和点击处理

这几部分的代码比较乱,但是没有什么新知识点,都是一些逻辑方面的内容,就不贴出来了
最后附件里会放出完整的demo代码,可以下载查看

------------------------------------------------------------------------------

4.表情的输入框插入和删除

实质上还是对表情对应的文本数据进行操作,这里最要注意的地方是输入框中的光标问题
输入框其实也是TextView的一种,显示和之前介绍的方法一样,
但是动态的添加和删除就需要注意处理位置的问题了

a.手动设置光标
新添加一个表情,应该是在输入框中当前光标的位置插入图片,所以首先要知道光标的位置
获取这里可以用 et.setSelectionStart方法
还有一点,添加完表情以后,光标应该更新到新添加内容后面,
而设置光标位置就要用 et.setSelection(position)方法

b.调用系统按钮事件自动处理
删除就比较简单了,这里直接调用系统的 Delete 按钮事件即可,
让某个控件调用按钮事件的方法为
et.displatchKeyEvent(new KeyEvent(action, code));
其中action就是动作,用ACTION_DOWN按下动作就可以了
而code为按钮事件码,删除对应的就是KEYCODE_DEL

------------------------------------------------------------------------------

5.表情添加脚本

以上,知识点就全部介绍完毕了,最后是福利时间
表情少则几十,多则甚至上百~ 一个一个的根据名字设置对应表情键值对会各种痛苦
这里推荐编写脚本进行处理,也就是写段功能自动的生成所需代码

这段就比较灵活了,需要根据不同需要编写脚本,所以主要是提供个思路然后以微博为例编写代码

微博中表情是"[表情文字]",而表情图片名字则是"d_表情拼音"
(此外还有其他的名字样式,比如h_或者emoji_等等,暂时不管,处理原理都差不多)

这里要先说明一下前提,必须要按照一定规则来才能进行这种半自动化的处理,
如果表情干脆名字就是瞎起的,那就没辙了,
如果是公司自己做应用的话,一定要让美工切图后导出的图片文件名按照套路出牌

新浪微博中d_表情拼音这里就都是中文对应的拼音而非英文,且中文都是和[表情文字]一致的,
比如害羞表情的文字就是[害羞],而图片名字就是d_haixiu

那微博这里处理就可以按照套路来了
1) 打开微博原版客户端,把所有表情全部选中,然后发出来
2) 在日志里获取到这段图片对应的文字数据
3) 用表情文字规则对这段文字进行循环匹配
4) 每次循环的时候都,把匹配的表情名字转为拼音(pinyin4j等工具)
5) 把表情文字转成的拼音再拼成图片资源的名字(微博这里就是加个"d_"前缀)
6) 拼接map.put的代码
7) 循环完成后,打印出来全部的map.put代码,然后复制到我们的表情工具类中使用

贴上代码,脚本直接新建一个java的项目放在main函数里运行就可以了

  1. public static void weiboEmoji() {
  2. StringBuilder sb = new StringBuilder();
  3. String names = "[羞羞哒甜馨][萌神奥莉][带着微博去旅行][爱红包][拍照][马到成功]→_→[呵呵][嘻嘻][哈哈][爱你][挖鼻屎][吃惊][晕][泪][馋嘴][抓狂][哼][可爱][怒][汗][害羞][睡觉][钱][偷笑][笑cry][doge][喵喵][酷][衰][闭嘴][鄙视][花心][鼓掌][悲伤][思考][生病][亲亲][怒骂][太开心]" +
  4. "[懒得理你][右哼哼][左哼哼][嘘][委屈][吐][可怜][打哈气][挤眼][失望][顶][疑问][困][感冒][拜拜][黑线][阴险][打脸][傻眼][互粉][心][伤心][猪头][熊猫][兔子]" ;
  5. String regexEmoji = "\\[([\u4e00-\u9fa5a-zA-Z0-9])+\\]" ;
  6. Pattern patternEmoji = Pattern. compile(regexEmoji);
  7. Matcher matcherEmoji = patternEmoji.matcher(names);
  8. CharacterParser parser = CharacterParser. getInstance();
  9. while (matcherEmoji.find()) { // 如果可以匹配到
  10. String key = matcherEmoji.group(); // 获取匹配到的具体字符
  11. String pinyinName = "d_" + parser.getSpelling(key).replace("[" , "" ).replace("]" , "" );
  12. sb.append( "emojiMap.put(\"" + key + "\", R.drawable." + pinyinName + ");\n" );
  13. }
  14. System. out.println(sb.toString());
  15. }

复制代码

运行结果,从控制台复制代码粘贴到项目里的工具类中即可

可能有的表情文件名就是不按套路来,
比如新浪微博这里的笑哭的表情,文字就是[笑cry],而图片文件名是d_xiaoku
那么也没关系,你复制到项目中,如果图片资源匹配不上的话也会报错提示,进行对应修改即可

------------------------------------------------------------------------------

Android 表情功能的完整处理方案相关推荐

  1. Android 表情功能实现,封装面板方便使用

    最近项目要修改表情布局,看着那个心碎啊,好几个页面都用到了表情面板,以前的哥们不耐其凡的复制了好几份,每次都一大堆代码,看着心里有些无奈的抓狂. 原理:表情底层数据传输其实就是一个特殊文本传输,通过文 ...

  2. Android 支持表情功能

    概述 1.原理和实现思路 2.表情图片显示 3.表情面板 4.表情的输入框插入和删除 5.表情添加脚本 Android中表情功能,一般都不是用ImageView去设置图片实现的, 表情一般会嵌套在文本 ...

  3. android 新浪微博客户端的表情功能的实现

    这是一篇好文章,我转来收藏,技术的最高境界是分享. 最近在搞android 新浪微博客户端,有一些心得分享 弄android客户端表情功能可以用以下思路 1.首页把新浪的表情下载到本地一文件夹种,表情 ...

  4. android简单小程序完整代码_10行代码实现小程序支付功能!丨实战

    " 纯干货!本文教你用云开发轻松实现强大的小程序支付功能! " 导语 前面给大家讲过如何借助小程序云开发实现微信支付,但是这种开发方式相对繁琐,并且具有不稳定性,今天就给大家讲一下 ...

  5. Android P功能

    Android P Preview was launched a few months back and we're still in awe of the new features that hav ...

  6. android表情面板_Android Q:应用内设置面板

    android表情面板 In this tutorial, we'll be discussing how to show the Settings Panel in our android appl ...

  7. Android视频点播-边播边缓存-方案

    Android视频点播-边播边缓存-方案 简述 一些知名的视频app客户端(优酷,爱奇艺)播放视频的时候都有一些缓存进度(二级进度缓存),qq,微信有关的小视频,还有一些短视频app,都有边播边缓的处 ...

  8. IM界面高仿微信,android表情转ios表情,支持自定义表情,支持语音(实战界面)

    前言: 2018年底由子公司来到现在的集团公司,从互联网公司变成了企业公司.在最近一个项目里,做的辛辛苦苦,功能又被砍了.没有理由,心力交瘁!本来是打算自己做IM的,现在被砍了.我就把本地功能贡献出来 ...

  9. Android 分享功能之 微信 图片分享

    前言:如果 有关 QQ好友 纯文本分享的问题 ,可点查看 Android 分享功能实现与 QQ 纯文本分享. 我们都知道,通过 微信官方 分享sdk 支持图片分享,而且有多种方式.官方链接 可直接查看 ...

最新文章

  1. 用WPF山寨折线图,抄?是狠狠的抄
  2. [LeetCode 123] - 买入与卖出股票的最佳时机III(Best Time to Buy and Sell Stock III)
  3. 14.JAVA整型变量
  4. 微信上让人反感的5种行为 敢不敢看看你是否也犯过
  5. Java千百问_05面向对象(004)_java接口到底是什么
  6. python自动化办公excel-Python自动化办公系列之Python操作Excel
  7. python体验课是上纯代码_附实战代码|告别OS模块,体验Python文件操作新姿势!...
  8. doip 源码_DoIP技术(二)
  9. ezcad旋转轴标刻参数_激光打标机软件ezcad中菜单下的旋转角度标刻2功能介绍及其操作设置...
  10. 【转载】阿里数据技术大图详解
  11. 三角函数:直角三角形内角关系公式
  12. JQuery中$(document)、$(document).ready()是什么意思?
  13. 我的世界php motd,我的世界MOTD攻击服务器 频繁发送请求
  14. MATLAB 绘制sinc函数的简单代码
  15. P100:045-使用Weevely工具上传一句话木马
  16. Pytorch学习之cuda
  17. iOS 屏幕录制 (可选录入麦克风的声音)
  18. 第二证券|卡塔尔给体育烧的钱,不止世界杯
  19. 真实案例:用照片做成动态图能从苹果手机盗走微信支付宝里的钱?
  20. 华为手机怎么设置初一十五提醒

热门文章

  1. 下一个7年,保持期待、持续思考,酷雷曼继续向前!
  2. 测试ResNet在ImageNet验证集上的准确率
  3. 使用CDS下载ERA5数据(保姆级教程)
  4. WPS表格打印的时候有非常多的空白页应该怎么办?
  5. 2018华为网赛复赛感想
  6. android 开发蓝牙电子秤,GitHub - xiangbohua/scales-bridge: scales-bridge 电子称 蓝牙电子秤 连接库...
  7. Vue 仿淘宝购物车
  8. (Java实现) 最大团问题 部落卫队
  9. TP5使用PHPExcel将数据动态导出为Excel表格
  10. python3*1**3 表达式输出结果为_3*1**3 表达式输出结果为?_学小易找答案