- 論壇徽章:
- 0
|
我們在進(jìn)行qq聊天的時候發(fā)送表情,但這些表情都是并不是靜態(tài)的,更多的是動態(tài)圖,gif圖,那么如何在android客戶端顯示動態(tài)gif圖呢。
1.jpg (104.25 KB, 下載次數(shù): 69)
下載附件
2015-06-11 09:26 上傳
我們首先來看一下該開源項目的代碼。該開源項目主要是通過自定義一個Adapter-------chatAdapter,在ChatAdapter每一條的setText屬性中使用了自定義的方法convertNormalStringToSpannableString
2.png (38.18 KB, 下載次數(shù): 63)
下載附件
2015-06-11 09:26 上傳
convertNormalStringToSpannableString方法的返回值是SpannableString
我們首先來了解一下什么是SpannableString
TextView通常用來顯示普通文本,但是有時候需要對其中某些文本進(jìn)行樣式、事件方面的設(shè)置。Android系統(tǒng)通過SpannableString類來對指定文本進(jìn)行相關(guān)處理,也就是說我們想要實(shí)現(xiàn)文字加動態(tài)表情的實(shí)現(xiàn)就要通過SpannableString這個類來實(shí)現(xiàn)。- 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;
- }
復(fù)制代碼 首先將我們傳入的message轉(zhuǎn)化成SpannableString類,然后看一下傳入的值是否符合我們一開始寫好的正則表達(dá)式EMOTION_URL- private Pattern EMOTION_URL = Pattern.compile("\\[(\\S+?)\\]");
復(fù)制代碼 如果符合的話 我們?nèi)roup(0)
附:group是針對()來說的,group(0)就是指的整個串,group(1)指的是第一個括號里的東西,group(2)指的第二個括號里的東西。
子表達(dá)式和起始位置和結(jié)束位置的差小于8,也就是符合我們的要求。調(diào)用FaceManager中的getFaceId方法- public int getFaceId(String faceStr){
- if(mFaceMap.containsKey(faceStr)){
- return mFaceMap.get(faceStr);
- }
- return -1;
- }
復(fù)制代碼 找到我們用Map進(jìn)行存儲的表情
如果表情存在的話利用一個弱引用(WeakReference)把自定義的AnimatedImageSpan進(jìn)行處理,使AnimatedImageSpan不那么的消耗內(nèi)存,在UpdateListener中利用postInvalidate刷新界面。最后把SpannableString的setSpan方法,三個參數(shù)分別是要放進(jìn)去的span ,起始位置,結(jié)束位置,flag標(biāo)志。
關(guān)于flag:- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE, 這是在 setSpan 時需要指定的 flag,它是用來標(biāo)識在 Span 范圍內(nèi)的文本前后輸入新的字符時是否把它們也應(yīng)用這個效果。分別有 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、 Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、 Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、 Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括)。
復(fù)制代碼 最后將SpannableString返回,實(shí)現(xiàn)動態(tài)圖文混排。
關(guān)于自定義的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();
- }
- }
復(fù)制代碼 |
|