我们在进行qq聊天的时候发送表情,但这些表情都是并不是静态的,更多的是动态图,gif图,那么如何在android客户端显示动态gif图呢。

  在github上找到了这样一种方法,Github地址https://github.com/TracyZhangLei/android-gif-demo

  由于我是截图,所以看不到动态效果,大家可以自己下载看一下。

  我们首先来看一下该开源项目的代码。该开源项目主要是通过自定义一个Adapter-------chatAdapter,在ChatAdapter每一条的setText属性中使用了自定义的方法convertNormalStringToSpannableString

  convertNormalStringToSpannableString方法的返回值是SpannableString

  我们首先来了解一下什么是SpannableString

  TextView通常用来显示普通文本,但是有时候需要对其中某些文本进行样式、事件方面的设置。Android系统通过SpannableString类来对指定文本进行相关处理,也就是说我们想要实现文字加动态表情的实现就要通过SpannableString这个类来实现。

private SpannableString convertNormalStringToSpannableString(String message , final TextView tv) {
SpannableString value = SpannableString.valueOf(message);
Matcher localMatcher = EMOTION_URL.matcher(value);
while (localMatcher.find()) {
String str2 = localMatcher.group(0);
int k = localMatcher.start();
int m = localMatcher.end();
if (m - k < 8) {
int face = fm.getFaceId(str2);
if(-1!=face){//wrapping with weakReference
WeakReference<AnimatedImageSpan> localImageSpanRef = new WeakReference<AnimatedImageSpan>(new AnimatedImageSpan(new AnimatedGifDrawable(cxt.getResources().openRawResource(face), new AnimatedGifDrawable.UpdateListener() {
@Override
public void update() {//update the textview
tv.postInvalidate();
}
})));
value.setSpan(localImageSpanRef.get(), k, m, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
}
}
return value;
}

  首先将我们传入的message转化成SpannableString类,然后看一下传入的值是否符合我们一开始写好的正则表达式EMOTION_URL

private Pattern EMOTION_URL = Pattern.compile("\\[(\\S+?)\\]");

  如果符合的话 我们取group(0)

  附:group是针对()来说的,group0)就是指的整个串,group1指的是第一个括号里的东西,group2)指的第二个括号里的东西。

  子表达式和起始位置和结束位置的差小于8,也就是符合我们的要求。调用FaceManager中的getFaceId方法

public int getFaceId(String faceStr){
if(mFaceMap.containsKey(faceStr)){
return mFaceMap.get(faceStr);
}
return -1;
}

  找到我们用Map进行存储的表情

  如果表情存在的话利用一个弱引用(WeakReference)把自定义的AnimatedImageSpan进行处理,使AnimatedImageSpan不那么的消耗内存,在UpdateListener中利用postInvalidate刷新界面。最后把SpannableString的setSpan方法,三个参数分别是要放进去的span ,起始位置,结束位置,flag标志。

  关于flag:

  Spanned.SPAN_EXCLUSIVE_EXCLUSIVE, 这是在 setSpan 时需要指定的 flag,它是用来标识在 Span 范围内的文本前后输入新的字符时是否把它们也应用这个效果。分别有 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、 Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、 Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、 Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括)。

  最后将SpannableString返回,实现动态图文混排。

  关于自定义的AnimatedImageSpan如下:

public class AnimatedImageSpan extends DynamicDrawableSpan {

    private Drawable mDrawable;

    public AnimatedImageSpan(Drawable d) {
super();
mDrawable = d;
// Use handler for 'ticks' to proceed to next frame
final Handler mHandler = new Handler();
mHandler.post(new Runnable() {
public void run() {
((AnimatedGifDrawable)mDrawable).nextFrame();
// Set next with a delay depending on the duration for this frame
mHandler.postDelayed(this, ((AnimatedGifDrawable)mDrawable).getFrameDuration());
}
});
}
@Override
public Drawable getDrawable() {
return ((AnimatedGifDrawable)mDrawable).getDrawable();
} @Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
Drawable d = getDrawable();
Rect rect = d.getBounds(); if (fm != null) {
fm.ascent = -rect.bottom;
fm.descent = 0; fm.top = fm.ascent;
fm.bottom = 0;
} return rect.right;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
Drawable b = getDrawable();
canvas.save(); int transY = bottom - b.getBounds().bottom;
if (mVerticalAlignment == ALIGN_BASELINE) {
transY -= paint.getFontMetricsInt().descent;
} canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
}

  如果大家有疑问,欢迎加入QQ群: (452379712),与杰瑞教育高级工程师在线互动

作者:杰瑞教育
出处:http://www.cnblogs.com/jerehedu/ 
本文版权归烟台杰瑞教育科技有限公司和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
 

最新文章

  1. Lesson 1 A private conversation
  2. SQLServer学习笔记系列11
  3. 搞ACM的你伤不起[转自RoBa]------(看一次,笑一次)
  4. iOS----Asset Catalog的用法
  5. 伪类link,hover,active,visited,focus的区别
  6. 01-CALayer的基本操作
  7. python中若干错误
  8. keybd_event 转载
  9. android HorizontalListView
  10. VS2008与opencv结合使用的方法
  11. es6编写reactjs事件处理函数绑定this三种方式
  12. Watson Explorer Analytical Components 2
  13. Cocos2D中相关问题提问的几个论坛
  14. vue之登录和token处理
  15. OpenGL step by step 38 : Skeletal Animation with Assimp
  16. React Native之FlexBox布局
  17. Spring MVC 学习笔记8 —— 实现简单的用户管理(4)用户登录
  18. 一台电脑配置多个tomcat过程
  19. 【LOJ】#2069. 「SDOI2016」齿轮
  20. 【LG4585】[FJOI2015]火星商店问题

热门文章

  1. Revit二次开发示例:ChangesMonitor
  2. BZOJ 3956: Count 主席树 可持久化线段树 单调栈
  3. 【差分约束系统/DFS版SPFA】BZOJ3436-小K的农场
  4. 【ZOJ】3740:Water Level【DP】
  5. hdu 3949 第k大异或组合
  6. Python环境右键定制
  7. Codeforces #254 div1 B. DZY Loves FFT 暴力乱搞
  8. Codeforces Round #228 (Div. 1) A. Fox and Box Accumulation 贪心
  9. Pycharm报错解决:error:please select a valid Python interpreter
  10. js异步任务处理方式