- 论坛徽章:
- 0
|
我们在进行qq聊天的时候发送表情,但这些表情都是并不是静态的,更多的是动态图,gif图,那么如何在android客户端显示动态gif图呢。
我们首先来看一下该开源项目的代码。该开源项目主要是通过自定义一个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是针对()来说的,group(0)就是指的整个串,group(1)指的是第一个括号里的东西,group(2)指的第二个括号里的东西。
子表达式和起始位置和结束位置的差小于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();
- }
- }
复制代码 |
|