android自定義GifView顯示gif動畫

  gif動畫在web開發中使用的非常的多,利用gif,許多動畫不必再用程序編寫,現在有非常多的App已經使用到了gif動畫,可是android sdk並沒有爲我們提供gif這種View,所以我們只能自定義一個View,去實現gif效果.

   android雖然沒有爲我們提供現成的GifView,但是爲我們提供了Movie類,這個類就是用來實現GifView的關鍵類.它主要有兩個最重要的方法,一個是根據動畫播放時間設置當前要現顯示的幀,二是將當前要顯示的幀繪製到畫布中.下面看一下效果圖:

點擊暫停按鈕還可以暫停gif動畫.

   下面就看是如何實現的:

    1.首先將需要用到的屬性先自定義好:如下代碼所示:

 

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="gifCommon">
        <attr name="gif_src" format="reference" />
        <attr name="decode_stream" format="boolean" />
        <attr name="default_animation_time" format="integer" />
    </declare-styleable>

</resources>
   三個屬性分別代表:gif資源,是否採用流編碼,默認動畫間隔時間.

   2.自定義GifView代碼.

package view;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.util.AttributeSet;
import android.view.View;

import com.example.drawbaledemo.R;

/**
 * @author rzq
 *
 */
public class GifView extends View {

	private Movie mMovie;
        /**
         * 動畫開始時間
         /
        private long mMovieStart;
	private boolean mPaused = false;
        /**
         * 當前幀動畫時間
         /
        private int mCurrentAnimationTime ;
	/**
         * 自定義的三個屬性
         /
        private boolean decode_STREAM;
	private int src_ID;
	private int default_time;

	public GifView(Context context) {
		super(context);
		init(context, null);
	}

	public GifView(Context context, AttributeSet set) {
		super(context, set);
		init(context, set);
	}

	private void init(Context context, AttributeSet set) {

		TypedArray a = context.obtainStyledAttributes(set,
				R.styleable.gifCommon);
		src_ID = a.getResourceId(R.styleable.gifCommon_gif_src, -1);
		decode_STREAM = a.getBoolean(R.styleable.gifCommon_decode_stream, true);
		default_time = a.getInteger(
				R.styleable.gifCommon_default_animation_time, 1000);
		a.recycle();

		setFocusable(true);
		java.io.InputStream is;
		is = context.getResources().openRawResource(src_ID);

		if (decode_STREAM) {
			mMovie = Movie.decodeStream(is);    // 根據文件流創建Movier繪製對象
		} else {
			byte[] array = streamToBytes(is);
			mMovie = Movie.decodeByteArray(array, 0, array.length);
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (mMovie != null) {
			if (!mPaused) {
				// 更新幀時間
				updateAnimationTime();
				drawMovieFrame(canvas);
				invalidate();
			} else {
				// 暫停時,不更新幀時間,則只畫當前幀
				drawMovieFrame(canvas);
			}
		}
	}

	private void updateAnimationTime() {
		long now = android.os.SystemClock.uptimeMillis();
		// 如果第一幀,記錄起始時間
		if (mMovieStart == 0) {
			mMovieStart = now;
		}
		// 取出動畫的時長
		int dur = mMovie.duration();
		if (dur == 0) {
			dur = default_time;
		}
		// 算出需要顯示第幾幀
		mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
	}

	private void drawMovieFrame(Canvas canvas) {
		// 設置要顯示的幀,繪製即可
		mMovie.setTime(mCurrentAnimationTime);
		canvas.save(Canvas.MATRIX_SAVE_FLAG);
		mMovie.draw(canvas, 0, 0);
		canvas.restore();
	}

	/**
	 * 設置暫停
	 * 
	 * @param paused
	 */
	public void setPaused(boolean paused) {
		this.mPaused = paused;
		if (!paused) {
			/**
			 * 更新動畫起點時間
			 */
			mMovieStart = android.os.SystemClock.uptimeMillis()
					- mCurrentAnimationTime;
		}
		invalidate();
	}

	/**
	 * 判斷gif圖是否停止了
	 * 
	 * @return
	 */
	public boolean isPaused() {
		return this.mPaused;
	}

	/**
	 * 重寫此方法,使自定義View支持wrap_content
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		int width;
		int height;
		if (widthMode == MeasureSpec.EXACTLY) {
			width = widthSize;
		} else {

			int desired = (int) (getPaddingLeft() + mMovie.width() + getPaddingRight());
			width = Math.min(desired,widthSize);
		}

		if (heightMode == MeasureSpec.EXACTLY) {
			height = heightSize;
		} else {
			int desired = (int) (getPaddingTop() + mMovie.height() + getPaddingBottom());
			height = Math.min(desired,heightSize);
		}

		setMeasuredDimension(width, height);
	}

	/**
	 * 將流轉化爲字節數組
	 * 
	 * @param is
	 * @return
	 */
	private static byte[] streamToBytes(InputStream is) {
		ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
		byte[] buffer = new byte[1024];
		int len;
		try {
			while ((len = is.read(buffer)) >= 0) {
				os.write(buffer, 0, len);
			}
		} catch (java.io.IOException e) {
		}
		return os.toByteArray();
	}

}
  3.佈局文件中使用GifView.

  

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:gif="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fed952"
    android:gravity="center" >

    <view.GifView
        android:id="@+id/gif_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        gif:decode_stream="true"
        gif:default_animation_time="1000"
        gif:gif_src="@drawable/animated_gif" />

    <TextView
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/gif_view"
        android:text="暫停" />

</RelativeLayout>
與使用普通的View一樣,將需要的資源傳入即可.

   

發佈了66 篇原創文章 · 獲贊 59 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章