天天看點

Android 中使用ImageView實作播放Gif圖檔功能

概述

最近在項目中遇到需要展示Gif圖檔的功能,我們知道原生ImageView是不支援播放Gif的,但是Android為我們提供了一個類可以實作該功能:android.graphics.Movie。

該類的實作思路

1.将Gig圖檔資源生成流的對象,然後Movie将流解碼成一個Movie的對象。

InputStream is = getResources().openRawResource(resourceId);
movie = Movie.decodeStream(is);
           

2.擷取Movie的動畫時長

int duration = movie.duration();
           

3.根據時間,繪制出對應每一幀的圖檔

int relTime = (int) ((now - mMovieStart) % duration);
movie.setTime(relTime);
movie.draw(canvas, , );
           

具體代碼實作

package com.example.powerimageviewtest;
import java.io.InputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * 繼承了ImageView原生的所有功能,還加入了播放GIF動畫的功能。
 * 
 */
public class GifImageView extends ImageView {

    /**
     * 播放GIF動畫的關鍵類
     */
    private Movie mMovie;

    /**
     * 記錄動畫開始的時間
     */
    private long mMovieStart;

    /**
     * GIF圖檔的寬度
     */
    private int mImageWidth;

    /**
     * GIF圖檔的高度
     */
    private int mImageHeight;

    /**
     * PowerImageView構造函數。
     * 
     * @param context
     */
    public GifImageView(Context context) {
        super(context);
    }

    /**
     * PowerImageView構造函數。
     * 
     * @param context
     */
    public GifImageView(Context context, AttributeSet attrs) {
        this(context, attrs, );
    }

    /**
     * PowerImageView構造函數,在這裡完成所有必要的初始化操作。
     * 
     * @param context
     */
    public GifImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        int resourceId = getResourceId(context, attrs);

        if (resourceId != ) {
            // 當資源id不等于0時,就去擷取該資源的流
            InputStream is = getResources().openRawResource(resourceId);
            // 使用Movie類對流進行解碼
            mMovie = Movie.decodeStream(is);
            if (mMovie != null) {
                // 如果傳回值不等于null,就說明這是一個GIF圖檔
                Bitmap bitmap = BitmapFactory.decodeStream(is);
                if(bitmap != null){
                    mImageWidth = bitmap.getWidth();
                    mImageHeight = bitmap.getHeight();

                    bitmap.recycle();
                }
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (mMovie == null) {
            // mMovie等于null,說明是張普通的圖檔,則直接調用父類的onDraw()方法
            super.onDraw(canvas);
        } else {
            // mMovie不等于null,說明是張GIF圖檔
            // 調用playMovie()方法播放GIF動畫
            if(!playMovie(canvas)){
                invalidate();
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mMovie != null) {
            // 如果是GIF圖檔則重寫設定PowerImageView的大小
            setMeasuredDimension(mImageWidth, mImageHeight);
        }
    }

    /**
     * 開始播放GIF動畫,播放完成傳回true,未完成傳回false。
     * 
     * @param canvas
     * @return 播放完成傳回true,未完成傳回false。
     */
    private boolean playMovie(Canvas canvas) {

        long now = SystemClock.uptimeMillis();

        if (mMovieStart == ) {
            mMovieStart = now;
        }

        int duration = mMovie.duration();

        if (duration == ) {
            duration = ;
        }

        int relTime = (int) ((now - mMovieStart) % duration);

        mMovie.setTime(relTime);
        mMovie.draw(canvas, , );

        if ((now - mMovieStart) >= duration) {
            //播放完成,顯示最後一幀
            mMovie.setTime(duration);
            mMovie.draw(canvas, , );
            return true;
        }

        return false;
    }

    /**
     * 擷取到src指定圖檔資源所對應的id。
     * 
     * @param context
     * @param attrs
     * @return 傳回布局檔案中指定圖檔資源所對應的id,沒有指定任何圖檔資源就傳回0。
     */
    private int getResourceId(Context context, AttributeSet attrs) {

        for (int i = ; i < attrs.getAttributeCount(); i++) {
            if (attrs.getAttributeName(i).equals("src")) {
                return attrs.getAttributeResourceValue(i, );
            }
        }
        return ;
    }

}
           

xml中調用方式

<com.example.powerimageviewtest.GifImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/start3" />
           

注意:

有時會遇到無法正常播放gif情況,這時需要在目前Acitvity中關閉硬體加速 android:hardwareAccelerated=”false”