前言:这段时间项目中需要将原来自定义表情更换为emoji表情,而且需要在各平台上都能解析,由于第一版中的表情是我做的,所以这个活又只能由我来折腾了。下面是移植到项目前的demo效果图,使用输入法中的emoji也可以解析。
实现思路:其实跟自定义表情实现基本上是一样的,只过自定义表情中的编码是自己定的,解析的时候使用正则匹配再替换就可以,而emoji要想平台通用,就得使用unicode编码(参考http://code.iamcal.com/php/emoji/),不过本菜鸟对编码这块不了解,差点就对它投降了。现在结合demo解释一下:
第一步:解析emoji(EmojiFileParser.java)
使用pull解析,将节点值转换为emoji的unicode与对应资源id的键值对,存放在SparseIntArray对象中,由于当时写的时候思路比较乱,所以代码不是很整洁,以后会注意的,下面只贴关键代码段,详细的大家可以看demo。
<span style="white-space:pre"> </span>/**
* @describe TODO 将表情的unicode以键值对的形式添加到集合中
* @param emoji
*/
private void addToMap(EmojiModel emoji) {
if(emoji.getUnicode().length() < 6)
emojiMap.put(emoji.getUnicode().codePointAt(0), emoji.getResId());
}
/**
* @describe TODO 将表情结点值转换为表情对象
* @param emojiCode xml中解析中节点值
* @return
*/
private EmojiModel convertToEmoji(String emojiCode) {
EmojiModel emoji = new EmojiModel();
//设置表情的资源id
emoji.setResId(context.getResources().getIdentifier("emoji_" + emojiCode,
"drawable", context.getPackageName()));
if (emojiCode.length() < 6) {//由一个unicode表示的表情
<span style="color:#ff0000;">//将xml节点值转换为unicode字符串
emoji.setUnicode(new String(Character.toChars(Integer.parseInt(emojiCode, 16))));</span>
//只装由一个unicode的表情添加到键值对集合中
addToMap(emoji);
}else{//由两个unicode表示的表情,解析的时候单独处理,所以不添加到映射集合中
String[] emos = emojiCode.split("-");
char[] char0 = Character.toChars(Integer.parseInt(emos[0], 16));
char[] char1 = Character.toChars(Integer.parseInt(emos[1], 16));
char[] unicode = new char[char0.length + char1.length];
for (int i = 0; i < char0.length; i++) {
unicode[i] = char0[i];
}
for (int i = char0.length; i < unicode.length; i++) {
unicode[i] = char1[i - char0.length];
}
emoji.setUnicode(new String(unicode));
}
return emoji;
}
第二步:分页显示(EmojiFragment.java)
这点跟自定义表情没有什么区别,网上的demo也很多。
第三步:解析emoji表情(EmojiConvertUtil.java)
解析主要由这个方法完成,
<span style="white-space:pre"> </span>/**
* @describe TODO 如果传入的字符串中包含表情unicode,则替换为相应的图片
* @param spanStr
* @param start 开始的索引位置
* @param length 需要处理的长度
*/
public void convert(Spannable spanStr, int start, int length){
//SpannableString spanStr = new SpannableString(msg);
//传入的字符串长度
int strLength = spanStr.length();
<span style="white-space:pre"> </span>//需要处理的字符串长度,如果没有指定长度,一般都是整个字符串
<span style="white-space:pre"> </span>int textLengthToProcessMax = strLength - start;
<span style="white-space:pre"> </span>//需要处理的字符串长度,如果指定的超过字符串长度范围,则为整个字符串长度
<span style="white-space:pre"> </span>int textLengthToProcess = (length < 0 || length >= textLengthToProcessMax) ? strLength : (length+start);
<span style="white-space:pre"> </span>int skip = 0;//索引移动的步长,有些字符要由两个char来表示
<span style="white-space:pre"> </span>int resId = 0;//资源id,等于0表示没有对应的资源
<span style="white-space:pre"> </span>for(int i=start; i<textLengthToProcess; i+=skip){
skip = 0;
resId = 0;
<span style="color:#ff6666;">int unicode = Character.codePointAt(spanStr, i);
skip = Character.charCount(unicode);</span>
if (unicode > 0xff) {//unicode不在assic范围内
<span style="white-space:pre"> </span>//获取对应资源id
<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>resId = emojiMap.get(unicode);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>//当前编码没的找到对应资源且当前位置还有需要处理的字符(主要处理由两个unicode表示的emoji)
<span style="white-space:pre"> </span>if(resId == 0 && i+skip < textLengthToProcess){
<span style="white-space:pre"> </span>int followUnicode = Character.codePointAt(spanStr, i + skip);
<span style="white-space:pre"> </span>if (followUnicode == 0x20e3) {
<span style="white-space:pre"> </span>int followSkip = Character.charCount(followUnicode);
<span style="white-space:pre"> </span>switch (unicode) {
case 0x0031:
resId = R.drawable.emoji_0031_20e3;
break;
case 0x0032:
resId = R.drawable.emoji_0032_20e3;
break;
case 0x0033:
resId = R.drawable.emoji_0033_20e3;
break;
case 0x0034:
resId = R.drawable.emoji_0034_20e3;
break;
case 0x0035:
resId = R.drawable.emoji_0035_20e3;
break;
case 0x0036:
resId = R.drawable.emoji_0036_20e3;
break;
case 0x0037:
resId = R.drawable.emoji_0037_20e3;
break;
case 0x0038:
resId = R.drawable.emoji_0038_20e3;
break;
case 0x0039:
resId = R.drawable.emoji_0039_20e3;
break;
case 0x0030:
resId = R.drawable.emoji_0030_20e3;
break;
case 0x0023:
resId = R.drawable.emoji_0023_20e3;
break;
default:
followSkip = 0;
break;
}
skip += followSkip;
}else {
int followSkip = Character.charCount(followUnicode);
switch (unicode) {
case 0x1f1ef:
resId = (followUnicode == 0x1f1f5) ? R.drawable.emoji_1f1ef_1f1f5 : 0;
break;
case 0x1f1fa:
resId = (followUnicode == 0x1f1f8) ? R.drawable.emoji_1f1fa_1f1f8 : 0;
break;
case 0x1f1eb:
resId = (followUnicode == 0x1f1f7) ? R.drawable.emoji_1f1eb_1f1f7 : 0;
break;
case 0x1f1e9:
resId = (followUnicode == 0x1f1ea) ? R.drawable.emoji_1f1e9_1f1ea : 0;
break;
case 0x1f1ee:
resId = (followUnicode == 0x1f1f9) ? R.drawable.emoji_1f1ee_1f1f9 : 0;
break;
case 0x1f1ec:
resId = (followUnicode == 0x1f1e7) ? R.drawable.emoji_1f1ec_1f1e7 : 0;
break;
case 0x1f1ea:
resId = (followUnicode == 0x1f1f8) ? R.drawable.emoji_1f1ea_1f1f8 : 0;
break;
case 0x1f1f7:
resId = (followUnicode == 0x1f1fa) ? R.drawable.emoji_1f1f7_1f1fa : 0;
break;
case 0x1f1e8:
resId = (followUnicode == 0x1f1f3) ? R.drawable.emoji_1f1e8_1f1f3 : 0;
break;
case 0x1f1f0:
resId = (followUnicode == 0x1f1f7) ? R.drawable.emoji_1f1f0_1f1f7 : 0;
break;
default:
followSkip = 0;
break;
}
skip += followSkip;
}
}
<span style="white-space:pre"> </span>if(resId != 0){
spanStr.setSpan(getImageSpan(resId), i, i+skip,
<span style="white-space:pre"> </span> Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
在EditText中要解析系统键盘的emoji,则需要重写一下EditText(EmojiEditText.java).
@Override
protected void onTextChanged(CharSequence text, int start,
int lengthBefore, int lengthAfter) {
//将后添加的字符串进行处理
EmojiConvertUtil.getInstance(getContext()).convert(getText(), start, lengthAfter);
}
</pre><pre name="code" class="java"><strong>结语</strong>:demo中对所有的表情都进行了解析并分了类,只是自己项目中只需要用到其中的一些,所以没有全部显示,另外有些特殊的表情(由两个unicode表示的emoji),本菜鸟并没有做测试,所以大家需要留意。下载地址:<a target=_blank href="http://download.csdn.net/detail/ihuaren/8212245">点击打开链接</a><span style="font-family: Arial, Helvetica, sans-serif;">(上传时一直提示在百分之九十九就不动了,不知道可不可以用)</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
</pre><pre name="code" class="java"><strong>参考资料:</strong>
1、https://github.com/rockerhieu/emojicon
2、http://www.cnblogs.com/stay/archive/2012/10/30/2746489.html