Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android實現可播放GIF動畫的ImageView

Android實現可播放GIF動畫的ImageView

編輯:關於Android編程

Android的原生控件並不支持播放GIF格式的圖片。我們都知道,在Android中如果想要顯示一張圖片,可以借助ImageView來完成,但是如果將一張GIF圖片設置到ImageView裡,它只會顯示這張圖片的第一幀,不會產生任何的動畫效果。今天我們來編寫一個自定義的增強型ImageView(繼承ImageView),可以播放GIF格式的圖片,暫且叫做GifImageView吧。

1.自定義屬性

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 <declare-styleable name="GifImageView"> 
  <attr name="auto_play" format="boolean"></attr> 
 </declare-styleable> 
</resources>

 2.自定義View中獲取屬性值

 private Movie mMovie;//播放動畫需要用到的,系統類
 private int mImageWidth;//動畫的imageview的寬度
 private int mImageHeight;//動畫imageview的高度
 private long mMovieStart = 0;// 播放開始
 private boolean isAutoPlay;//是否自動播放
 private Bitmap mStartPlay;//開始按鈕
 private boolean isPlaying=false;//記錄是否正在播放
 private float mScale;//圖片的縮放比
 private int mMeasuredGifWidth;//縮放後圖片寬
 private int mMeasuredGifHeight;//縮放後圖片高
 ...

 private void init(Context context, AttributeSet attrs) {
 TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.GifImageView);
 // 通過反射拿布局中src的資源id,所以gif文件需要放在布局的src中
 int resourceId = getResourceId(attributes, context, attrs);
 if (resourceId != 0) {
  // 說明是gif動畫
  // 1.將resourcesId變成流
  // 2.用Move來decode解析流
  // 3.獲得bitmap的長寬
  InputStream is = getResources().openRawResource(resourceId);
  mMovie = Movie.decodeStream(is);
  if (mMovie != null) {
  Bitmap bitmap = BitmapFactory.decodeStream(is);
  mImageWidth = bitmap.getWidth();
  mImageHeight = bitmap.getHeight();
  // 用完釋放
  bitmap.recycle();
  // 獲得是否允許自動播放,如果不允許自動播放,則初始化播放按鈕
  isAutoPlay = attributes.getBoolean(R.styleable.GifImageView_auto_play, false);
  if (!isAutoPlay) {
   mStartPlay = BitmapFactory.decodeResource(getResources(),R.drawable.start_play);
   setOnClickListener(this);
  }  
  }
 }
 //回收資源
 attributes.recycle();
 }

 /**
 * 通過反射拿布局中src的資源id
 * 
 * @param attrs
 * @param context
 * @param attributes
 */
 private int getResourceId(TypedArray attributes, Context context, AttributeSet attrs) {
 try {
  Field filed = TypedArray.class.getDeclaredField("mValue");
  filed.setAccessible(true);
  TypedValue typeValue = (TypedValue) filed.get(attributes);
  return typeValue.resourceId;
 } catch (Exception e) {
  e.printStackTrace();
 }
 }
 return 0;
}

3.重寫onMesure()

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 if (mMovie != null) {
  /*
   * Calculate horizontal scaling
   */
  float scaleW = 1f;
  int measureModeWidth = MeasureSpec.getMode(widthMeasureSpec);
  if (measureModeWidth != MeasureSpec.UNSPECIFIED) {
   int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
   scaleW = (float) mImageWidth / (float) maximumWidth;
  }
  /*
   * calculate vertical scaling
   */
  float scaleH = 1f;
  int measureModeHeight = MeasureSpec.getMode(heightMeasureSpec);
  if (measureModeHeight != MeasureSpec.UNSPECIFIED) {
   int maximumHeight = MeasureSpec.getSize(heightMeasureSpec);
   scaleH = (float) mImageHeight / (float) maximumHeight;
  }
  /*
   * calculate overall scale
   */
  mScale = 1f / Math.max(scaleH, scaleW);
  mMeasuredGifWidth = (int) (mImageWidth * mScale);
  mMeasuredGifHeight = (int) (mImageHeight * mScale);
  setMeasuredDimension(mMeasuredGifWidth, mMeasuredGifHeight);
 }
 }

4.重寫onDraw()

 @Override
 protected void onDraw(Canvas canvas) {
 if (mMovie == null) {
  // mMovie等於null,說明是張普通的圖片,則直接調用父類的onDraw()方法
  super.onDraw(canvas);
 } else {
  // mMovie不等於null,說明是張GIF圖片
  if (isAutoPlay) {
  // 如果允許自動播放,就播放
  playMovie(canvas);
  invalidate();
  } else {
  // 不允許自動播放的話
  // 1.判斷是否正在播放
  // 2.獲得第一幀的圖像
  // 3.然後添加播放按鈕
  if (isPlaying) {
   // 如果正在播放就playmoive繼續播放
   if (playMovie(canvas)) {
   isPlaying = false;
   }
   invalidate();
  } else {
   // 第一幀
   mMovie.setTime(0);
   canvas.save(Canvas.MATRIX_SAVE_FLAG);
   canvas.scale(mScale, mScale);
   mMovie.draw(canvas, 0, 0);// 畫
   canvas.restore();
   // 繪制開始按鈕
   int offsetW = (mMeasuredGifWidth - mStartPlay.getWidth()) / 2;
   int offsetH = (mMeasuredGifHeight - mStartPlay.getHeight()) / 2;
   canvas.drawBitmap(mStartPlay, offsetW, offsetH, null);
  }
  }
 }
 }

 /**
 * 播放gif動畫
 * 
 * @param canvas
 */
 private boolean playMovie(Canvas canvas) {
 // 1.獲取播放的時間
 // 2.如果開始start=0,則認為是開始
 // 3.記錄播放的時間
 // 4.設置進度
 // 5.畫動畫
 // 6.如果時間大於了播放的時間,則證明結束
 long now = SystemClock.uptimeMillis();
 if (mMovieStart == 0) {
  mMovieStart = now;
 }
 int duration = mMovie.duration();
 if (duration == 0) {
  duration = 1000;
 }
 //記錄gif播放了多少時間
 int relTime = (int) ((now - mMovieStart) % duration);
 mMovie.setTime(relTime);// 設置時間
 canvas.save(Canvas.MATRIX_SAVE_FLAG);
 canvas.scale(mScale, mScale);
 mMovie.draw(canvas, 0, 0);// 畫
 canvas.restore();
 if ((now - mMovieStart) >= duration) {
  // 結束
  mMovieStart = 0;
  return true;
 }
 return false;
 }

5.添加點擊事件

 @Override
 public void onClick(View v) {
 if(v.getId()==getId()){
  isPlaying=true;
  invalidate();
 }
 }

還有一點需要注意,有些4.0以上系統的手機啟動了硬件加速功能之後會導致GIF動畫播放不出來,因此我們需要在AndroidManifest.xml中去禁用硬件加速功能,可以通過指定android:hardwareAccelerated=false來完成。

--------------------------------------------------------------------------------

現在我們來看看運行後效果如何吧,
布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 xmlns:attr="http://schemas.android.com/apk/res/com.hx.gifimageview"
 android:id="@+id/container"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

 <com.hx.gifimageview.GifImageView
  android:layout_width="150dip"
  android:layout_height="150dip"
  android:layout_margin="10dp"
  android:src="@drawable/shulan"
  attr:auto_play="false" />

 <com.hx.gifimageview.GifImageView
  android:layout_width="150dip"
  android:layout_height="150dip"
  android:layout_margin="10dp"
  android:src="@drawable/shulan"
  attr:auto_play="true" />

 <com.hx.gifimageview.GifImageView
  android:layout_width="150dip"
  android:layout_height="150dip"
  android:layout_margin="10dp"
  android:src="@drawable/jingtai"
  attr:auto_play="true" />
</LinearLayout>

 

圖一的auto_play屬性為false,會顯示第一幀和一個播放按鈕,點擊後Gif圖片會自動運行。
圖二的auto_play屬性為true,會自動循環播放Gif。
圖三我們給的資源是靜態圖片,因為自定義View繼承ImageView,所以具備ImageView所有特性,因此也能顯示靜態圖片。

源碼下載:http://xiazai.jb51.net/201609/yuanma/GifImageView(jb51.net).rar

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved