吐槽:第一次写博客,新手一枚。写这个博客为了共享一下资源,大家相互学习,最主要目的是抛砖引玉,引大婶指高见。
前言:需求是这样的,搞聊天,而且是在一个字库里面没有emoji的android系统里面搞。我收到的数据格式是这样的“我是新来的< emoji1f639 >”、”我是新来的[微笑]”。其中< emoji1f639 >和[微笑]就是表情了,所以需要匹配里面的emoji表情和QQ表情。
首先是显示Emoji
(emoji说白了就是一套统一的Unicode编码,每一个编码索引一个emoji表情。emoji(えもじ)是岛国圣斗士发明的,会日语所以读起来很有感觉。)
效果图(我一般比较喜欢先看图再看码):
首先是判断是否有emoji在消息里面,因为emoji只需要替换消息的内容,所以首先处理。这里使用正则表达式来处理,判断是否满足条件,然后将匹配到的内容add到容器里面。
private boolean checkEmojiInText(String text){
if(text == null && text.equals(""))return false;
//正则:取<emoji 和 >之间的内容(包含<emoji 和 >)
Pattern p = Pattern.compile("<emoji(.*?)>");
Matcher matcher = p.matcher(text);
while (matcher.find()) {
emojiTabList.add(matcher.group());
}
if(emojiTabList.size() > 0){
return true;
}
return false;
}
上面方法如果返回ture,就证明有emoji躲在text里面,所以我们需要找出来它的位置并把它给替换成emoji编码。
emoji字符串转成16进制的int就得到Unicode了,然后用 0x1F639 替换掉之前的< emoji1f639>就可以了。
if(checkEmojiInText(message)){
for(int i = 0; i < emojiTabList.size(); i++){
String emojiTab = emojiTabList.get(i).replace("<emoji", "")
.replace(">", "")
.toUpperCase();
//string to 16进制 int
int code = Integer.valueOf(emojiTab, 16);
//转换成emoji
String emoji = String.valueOf(Character.toChars(code));
message = message.replace(emojiTabList.get(i), emoji);
}
LogUtils.i("new message is " + message);
emojiTabList.clear();
}
上面说了,我是在一个没有emoji表情的世界里玩emoji的,自然我就需要emoji的字库啦。千辛万苦找到了几套emoji font ttf,有ios的、htc的、三星等等,有性趣的朋友可以在下面下。
使用方法的话,很简单就是在引用放在assets里面的字库,然后textview setTypeface就可以了。
Typeface typeface = Typeface
.createFromAsset(mContext.getResources().getAssets(), "ColorEmojiFont.ttf");
textView.setTypeface(typeface );
然后到QQ表情
QQ表情的话,我是放在emoji之后才处理,因为emoji只是替换内容,QQ表情的话要用到
SpannableString,所以我放在后面处理。最终返回的结果是返回SpannableString,才能显示QQ表情。
SpannableString使用的话,给你一个跳板(某个大婶的博客)
Android开发之TextView高级应用
效果图(先看图再看码):
首先先判断是否有QQ表情在消息里面,这里继续用上正则表达式,判断’[’ 和’]’里面出现字符的个数。如果出现1~3个之间,证明有可能是表情。因为还不能准确地确定,所以把有一个结果add到容器里面先,然后再匹配。
private boolean checkFaceInText(String text){
if(text == null && text.equals(""))return false;
//正则:以[开头, 以]结尾,中间至少出现一个字符,但是不能超过三个
Pattern p = Pattern.compile("\\[.{1,3}?\\]");
Matcher matcher = p.matcher(text);
while (matcher.find()) {
faceTabList.add(matcher.group());
facePositionList.add(matcher.start());
}
if(faceTabList.size() > 0
&& facePositionList.size() > 0
&& faceTabList.size() == facePositionList.size()){
return true;
}
return false;
}
接着做一个准备工作,就是在assets里面的face_icon文件夹内将所有QQ表情图片匹配到容器里面,这里我匹配到三个容器,为什么呢?因为我喜欢。
public void prepareChatFace(){
if(mContext == null)return;
if(oneStringList.size() == 0 && twoStringList.size() == 0 && threeStringList.size() == 0){
try {
InputStream inputStream = mContext.getResources().getAssets().open(ASSETS_FACE_FILE);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
String lineInfo = null;
while ((lineInfo = bufferedReader.readLine()) != null) {
String[] infoContent = lineInfo.split(",");
FaceInfo faceInfo = new FaceInfo();
faceInfo.setFaceName(infoContent[1]);
faceInfo.setFaceResource(getImageFromAssetsFile(infoContent[0]));
//face tag lenght
int strLenght = infoContent[1].length();
switch (strLenght){
case 1:
oneStringList.add(faceInfo);
break;
case 2:
twoStringList.add(faceInfo);
break;
case 3:
threeStringList.add(faceInfo);
break;
default:
break;
}
}
} catch (IOException e) {
LogUtils.e("get assets file exception. error: " + e.getMessage());
e.printStackTrace();
}
LogUtils.i("prepare all chat face to assign list finish!");
}
}
这里有一个getImageFromAssetsFile 方法,是用来读取QQ表情的
private Bitmap getImageFromAssetsFile(String fileName) {
if(mContext == null)return null;
Bitmap image = null;
AssetManager am = mContext.getResources().getAssets();
try
{
InputStream is = am.open(ASSETS_FACE_RESOURCE_FLODER+ "/" + fileName + ".png");
image = BitmapFactory.decodeStream(is);
is.close();
if(image != null){
return image;
}
}
catch (IOException e) {
LogUtils.e("read face image exception, error: " + e.getMessage());
e.printStackTrace();
}
return null;
}
好啦好啦,继续继续。这里使用到SpannableString,将拿到的QQ表情放到ImageSpan里面,然后通过spannableString.setSpan把ImageSpan放到SpannableString里面,setSpan开始位置用indexOf得到,然后结束位置用开始位置加上分割出来的字符串长度就可以了。
//接着判断 face
SpannableString spannableString = new SpannableString(message);
if(checkFaceInText(message)){
//准备工作
prepareChatFace();
for (int i = 0; i < faceTabList.size(); i++) {
Bitmap res = findRelevantFace(faceTabList.get(i)
.replace("[", "")
.replace("]", ""));
if (res == null) continue;
ImageSpan imageSpan = new ImageSpan(mContext, res);
int startPos = facePositionList.get(i);
int endPos = startPos + faceTabList.get(i).length();
spannableString.setSpan(imageSpan, startPos, endPos,
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
faceTabList.clear();
facePositionList.clear();
}
这里有个findRelevantFace方法,作用是找到相应的QQ表情。
private Bitmap findRelevantFace(String text){
if(text == null && text.equals(""))return null;
switch (text.length()){
case 1:
for(FaceInfo faceInfo : oneStringList){
if(faceInfo.getFaceName().equals(text)){
return faceInfo.getFaceResource();
}
}
break;
case 2:
for(FaceInfo faceInfo : twoStringList){
if(faceInfo.getFaceName().equals(text)){
return faceInfo.getFaceResource();
}
}
break;
case 3:
for(FaceInfo faceInfo : threeStringList){
if(faceInfo.getFaceName().equals(text)){
return faceInfo.getFaceResource();
}
}
break;
}
return null;
}
好啦这样就大功告成啦!!!
总结
第一次写文章,有点乱,望见谅。错误之处请指出,相互学习。
其实还是省略了很多的,有性趣的朋友可以download我的demo看看, 就是一个很简单的demo。
demo size有点大,是as的。
下面是github地址
demo