android實現gif圖與文字混排


  我們在進行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群:JRedu技術交流 (452379712),與傑瑞教育高級工程師在線互動

 

作者: 傑瑞教育
出處: http://www.cnblogs.com/jerehedu/ 
本文版權歸煙台傑瑞教育科技有限公司和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM