国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android自定義View播放Gif動畫的示例

2019-10-22 18:25:21
字體:
來源:轉載
供稿:網友

前言

GIF是一種很常見的動態圖片格式,在Android中它的使用場景非常多,大到啟動頁動畫、小到一個Loading展示,都可以用GIF動畫來完成,使用也很方便,直接從美工那邊拿過來用就成。如果項目趕時間或者自定義原生動畫太麻煩,GIF都是一個很好的選擇,相比于最新的WEBP格式的動畫,也有更好的兼容性(畢竟已經出現很多年了)。

關于圖片加載我一直用的是Google推薦的 Glide ,圖片加載和緩存都做的很好,同樣也支持GIF動畫。不過Glide默認就是循環播放Gif,沒有開放相關的接口來控制Gif。這就使的我們不能很好地控制Gif的播放,比如控制播放開始時間、播放次數,播放暫停、播放開始、結束事件的監聽,雖然用Glide可能做到(網上說可以,但我沒找到方法),但操作也會很麻煩。

分析

除了第三方的庫,Android自帶的類 android.graphics.Movie 也可以用來加載播放Gif動畫,而且實現起來很簡單。

  • Movie decodeStream(InputStream is)
  • Movie decodeFile(String pathName)
  • Movie decodeByteArray(byte[] data, int offset,int length)

按來源分別可以從Gif文件的輸入流,文件路徑,字節數組中得到Movie的實列。然后我們可以通過操作Movie對象來操作Gif文件。

下面介紹下幾個方法:

int width() movie的寬,值等于gif圖片的寬,單位:px。

int height() movie的高,值等于gif圖片的高,單位:px。

int duration() movie播放一次的時長,也就是gif播放一次的時長,單位:毫秒。

boolean isOpaque() Gif圖片是否帶透明

boolean setTime(int relativeMilliseconds) 設置movie當前處在什么時間,然后找到對應時間的圖片幀,范圍0 ~ duration。返回是否成功找到那一幀。

draw(Canvas canvas, float , float y) draw(Canvas canvas, float x, float y, Paint paint) 

在Canves中畫出當前幀對應的圖像。x,y對應Movie左上角在Canves中的坐標。

以上就是Movie平常會用到大部分方法,下面就利用這些自定義VIew實現播放Gif動畫。

實現

首先定義一些需要的屬性,用于在布局文件中設置gif

<declare-styleable name="GIFVIEW">    <!--gif文件引用-->    <attr name="gifSrc" format="reference" />    <!--是否加載完自動播放-->    <attr name="authPlay" format="boolean" />    <!--播放次放,默認永遠播放-->    <attr name="playCount" format="integer" />  </declare-styleable>

然后定義Gifde的播放監聽器,來監聽各個時段的事件,都很簡單就不再介紹了:

public interface OnPlayListener {    void onPlayStart();    void onPlaying(int percent);    void onPlayPause(boolean pauseSuccess);    void onPlayRestart();    void onPlayEnd();  }

聲明類,直接繼承ImageView,這樣我們不僅可以顯示Gif動畫,也可以顯示普通圖片:

public class GifImageView extends AppCompatImageView

然后加載Gif圖片資源

public void setGifResource(int movieResourceId, OnPlayListener onPlayListener) {    mOnPlayListener = onPlayListener;    movie = Movie.decodeStream(getResources().openRawResource(movieResourceId));    if (movie == null) {      //如果movie為空,那么就不是gif文件,嘗試轉換為bitmap顯示      Bitmap bitmap = BitmapFactory.decodeResource(getResources(), movieResourceId);      if (bitmap != null) {        setImageBitmap(bitmap);        return;      }    }    movieDuration = movie.duration() == 0 ? DEFAULT_DURATION : movie.duration();    requestLayout();  }

調用requestLayout重新計算View大小,并重新繪制。

@Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    if (movie != null) {      int movieWidth = movie.width();      int movieHeight = movie.height();      setMeasuredDimension(movieWidth, movieHeight);    } else {      super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }  }

開始播放:

public void play(int counts) {    this.counts = counts;    reset();    if (mOnPlayListener != null) {      mOnPlayListener.onPlayStart();    }    invalidate();  }

不斷調用onDraw方法來繪制Gif當前時間的圖片幀:

@Override  protected void onDraw(Canvas canvas) {    if (movie != null) {      if (!mPaused && hasStart) {        drawMovieFrame(canvas);        invalidateView();      } else {        drawMovieFrame(canvas);      }    } else {      super.onDraw(canvas);    }  }  /**   * 畫出gif幀   */  private void drawMovieFrame(Canvas canvas) {    movie.setTime(getCurrentFrameTime());    movie.draw(canvas, 0.0f, 0.0f);  }

最核心的方法就是計算當前時間需要播放處于movie中的哪個時間段。

private int getCurrentFrameTime() {    if (movieDuration == 0)      return 0;      //因為有暫停,所以需要減去暫停時間    long now = SystemClock.uptimeMillis() - dealyTime;    int nowCount = (int) ((now - mMovieStart) / movieDuration);    if (counts != -1 && nowCount >= counts) {      hasStart = false;      if (mOnPlayListener != null) {        mOnPlayListener.onPlayEnd();      }    }    int currentTime = (int) ((now - mMovieStart) % movieDuration);    int percent = currentTime * 100 / movieDuration;    if (mOnPlayListener != null && hasStart) {      mOnPlayListener.onPlaying(percent);    }    return currentTime;  }

暫停Gif播放:

public void pause() {    if (movie != null && !mPaused && hasStart) {      mPaused = true;      invalidate();      mMoviePauseTime = SystemClock.uptimeMillis();      if (mOnPlayListener != null) {        mOnPlayListener.onPlayPause(true);      }    } else {      if (mOnPlayListener != null) {        mOnPlayListener.onPlayPause(false);      }    }  }

繼續Gif播放:

if (mPaused && mMoviePauseTime > 0) {        mPaused = false;        dealyTime = dealyTime + SystemClock.uptimeMillis() - mMoviePauseTime;        invalidate();        if (mOnPlayListener != null) {          mOnPlayListener.onPlayRestart();        }      }經過這些處理,我們就

能更好地控制Gif的播放流程了。下面簡單看下成品圖:

Android,播放Gif動畫,播放Gif

進階

倒敘播放

相信看了上面GifImageView的實現原理后,倒敘播放的實現也是很容易的。

public void playReserver() {    if (movie != null) {      reset();      reverse = true;      if (mOnPlayListener != null) {        mOnPlayListener.onPlayStart();      }      invalidate();    }  }
if (reverse) {          movie.setTime(movieDuration - getCurrentFrameTime());        } else {          movie.setTime(getCurrentFrameTime());        }

如下圖,狗子的頭已經從原來的左邊轉到右邊變成了現在的右邊轉到左邊(???)。

Android,播放Gif動畫,播放Gif

像播放視頻一樣播放Gif動畫

這部分是我在寫完GifView后想到的一點進階功能,既然我們已經實現了播放和暫停,即能控制在某個時間點播放指定的Gif圖片幀,如果再加入進度條,快進等功能,那么不就能做到和視頻播放器一樣的功能了嗎?限于篇幅,我只簡單實現了進度條功能,更多功能實現請移步Github,地址: GifView 。

Android,播放Gif動畫,播放Gif

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


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阆中市| 山西省| 酉阳| 邵东县| 呼伦贝尔市| 漾濞| 易门县| 乌海市| 鹰潭市| 揭西县| 弥渡县| 辽源市| 明水县| 宝山区| 满洲里市| 南川市| 双牌县| 芦溪县| 海淀区| 白河县| 广安市| 宝应县| 沾益县| 崇仁县| 丽江市| 无为县| 页游| 建德市| 朝阳市| 连平县| 紫阳县| 织金县| 酒泉市| 石景山区| 文安县| 新和县| 望城县| 军事| 祁东县| 紫阳县| 科技|