Emoji开源项目解读(二)自定义表情

介绍

上一节呢,我们解读了一个系统Emoji表情,这节呢, 我们谈谈自定义表情,如QQ、微信等,正好前两天看到一个仿QQ的一个应用,虽然还是有许多需要完善的地方, 不过对于自定义Emoji表情功能,做的也是比较成熟了,这里要谢谢白玉梁同学,下面我带领大家来一起学习一下他的这个功能实现。

 

根据上一节的分析呢,这节我就简要的直奔主题说了,页面布局、架构和流程都不说了。 感兴趣的可以自己看代码。

源码剖析

咱们先来看看他的assets资源文件夹

g文件夹放的是gif图,如

p文件夹放的是静态图

 

再来看看怎么添加表情

当选中GridView的某一个表情的时候,触发事件

  1. // 单击表情执行的操作  
  2. gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  3. @Override  
  4. public void onItemClick(AdapterView<?> parent, View view,int position, long id) {  
  5. try {  
  6. String png = ((TextView) ((LinearLayout) view).getChildAt(1)).getText().toString();  
  7. if (!png.contains("_del")) {// 如果不是删除图标  
  8. ExpressionUtil.insert(editText,ExpressionUtil.getFace(context,png));  
  9. else {  
  10. ExpressionUtil.delete(editText);  
  11. }  
  12. catch (Exception e) {  
  13. e.printStackTrace();  
  14. }  
  15. }  
  16. });  
注意这行代码

  1. ExpressionUtil.insert(editText,ExpressionUtil.getFace(context,png));  
就是添加表情的了

先来看看是怎么组装EditText的样式的呢?

  1. public static SpannableStringBuilder getFace(Context mContext,String png) {  
  2. SpannableStringBuilder sb = new SpannableStringBuilder();  
  3. try {  
  4. /** 
  5.  * 经过测试,虽然这里tempText被替换为png显示,但是但我单击发送按钮时,获取到輸入框的内容是tempText的值而不是png 
  6.  * 所以这里对这个tempText值做特殊处理 
  7.  * 格式:#[face/png/f_static_000.png]#,以方便判斷當前圖片是哪一個 
  8.  * */  
  9. String tempText = "[" + png + "]";  
  10. sb.append(tempText);  
  11. sb.setSpan(  
  12. new ImageSpan(mContext, BitmapFactory  
  13. .decodeStream(mContext.getAssets().open(png))), sb.length()  
  14. - tempText.length(), sb.length(),  
  15. Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);  
  16.    
  17. catch (Exception e) {  
  18. e.printStackTrace();  
  19. }  
  20.    
  21. return sb;  
  22. }  
大家可以看看这个类 SpannableStringBuilder 的继承关系,实现了 CharSequence 接口,相当于一个样式的建造者,看到 Builder 就很容易的会联想到建造者模式的,功能如其名,的确也是这样做的。

这是设置好字符串后,又设置了ImageSpan样式,在指定的位置设置图片样式。

然后就是设置EditTextCharSequence 

  1. /** 
  2.  * 向输入框里添加表情 
  3.  * */  
  4. public static void insert(EditText input,CharSequence text) {  
  5. int iCursorStart = Selection.getSelectionStart((input.getText()));  
  6. int iCursorEnd = Selection.getSelectionEnd((input.getText()));  
  7. if (iCursorStart != iCursorEnd) {  
  8. ((Editable) input.getText()).replace(iCursorStart, iCursorEnd, "");  
  9. }  
  10. int iCursor = Selection.getSelectionEnd((input.getText()));  
  11. ((Editable) input.getText()).insert(iCursor, text);  
  12. }  
分为 2 种,和之前分析的系统表情方式差不多,假如游标不一致,其实就是选中了多个,就先用空串替换掉选中的表情,其实就是删除掉了,然后取得最新的游标,添加需要添加的表情。

然后来看看删除表情

ExpressionUtildelete方法

  1. /** 
  2.  * 删除图标执行事件 
  3.  * 注:如果删除的是表情,在删除时实际删除的是tempText即图片占位的字符串,所以必需一次性删除掉tempText,才能将图片删除 
  4.  * */  
  5. public static void delete(EditText input) {  
  6. if (input.getText().length() != 0) {  
  7. int iCursorEnd = Selection.getSelectionEnd(input.getText());  
  8. int iCursorStart = Selection.getSelectionStart(input.getText());  
  9. if (iCursorEnd > 0) {  
  10. if (iCursorEnd == iCursorStart) {  
  11. if (isDeletePng(input,iCursorEnd)) {  
  12. String st = "[p/_000.png]";  
  13. ((Editable) input.getText()).delete(  
  14. iCursorEnd - st.length(), iCursorEnd);  
  15. else {  
  16. ((Editable) input.getText()).delete(iCursorEnd - 1,  
  17. iCursorEnd);  
  18. }  
  19. else {  
  20. ((Editable) input.getText()).delete(iCursorStart,  
  21. iCursorEnd);  
  22. }  
  23. }  
  24. }  
  25. }  
这个删除表情的做法和上一节介绍的就明显不同了, 上次那个是系统表情,也就是说是系统字符单元,直接交给 EditText ,系统就会自动删除,当然前提是给他一个删除的事件额。

这个方法的备注要明确说明了,删除是删除图片占位的字串,这里有3种情况,第1种是删除游标内的内容,这个比较简单,直接取得游标的起止位置,删除掉就好了,第2种是删除普通文字,这个只要删除最后一个字符就好了, 最后一种就比较复杂了,是删除表情,大家来想一下,是不是首先得知道我要删除的是不是表情吧?

这里用到了ExpressionUtilisDeletePng方法

  1. /** 
  2.  * 判断即将删除的字符串是否是图片占位字符串tempText 如果是:则讲删除整个tempText 
  3.  * **/  
  4. public static boolean  isDeletePng(EditText input,int cursor) {  
  5. String st = "[p/_000.png]";  
  6. String content = input.getText().toString().substring(0, cursor);  
  7. if (content.length() >= st.length()) {  
  8. String checkStr = content.substring(content.length() - st.length(),content.length());  
  9. String regex = "\\[[^\\]]+\\]";  
  10. Pattern p = Pattern.compile(regex);  
  11. Matcher m = p.matcher(checkStr);  
  12. return m.matches();  
  13. }  
  14. return false;  
  15. }  
我觉得这个方法是整个项目的难点重点,作者的实现方法也比较优雅,这里的策略是根据咱们商量的添加表情的格式,来倒推最后一个应该去匹配是不是表情的字串,如果符合表情的标准就是了,这里在裁剪出目标检查表情后,用了正则表达式来做了一次匹配,不会正则的真的要好好学习了,有的时候,可以起到很好的效果,好了这样是不是要删除的表情的方法就讲解完了。

如果检查是表情的话,紧接着就是删除了,也就是删除的起止位置,结束位置知道了, 开始位置就是结束位置减去表情格式字符数就是喽。

 

到目前为止呢, 自定义表情的实现分析就已经结束了,结合上一节的系统表情,Emoji表情的分析就到此结束了。后续大家如果还有什么问题,或者有不正确的地方, 可以提出来,共同探讨。

 

项目地址

白玉梁的专栏 http://blog.csdn.net/baiyuliang2013/article/details/43073861

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值