91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2020-09-29 14:59:19 來源:腳本之家 閱讀:237 作者:大頭呆 欄目:移動開發

前言

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自定義View播放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自定義View播放Gif動畫的示例

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

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

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

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宾阳县| 茌平县| 贵溪市| 敦煌市| 沁水县| 城市| 招远市| 木里| 景德镇市| 津南区| 察隅县| 永城市| 蛟河市| 峨山| 成都市| 张家口市| 夏邑县| 长垣县| 广宗县| 日土县| 彩票| 大渡口区| 桃园市| 西青区| 苏尼特右旗| 綦江县| 岳西县| 合水县| 揭西县| 祁阳县| 东平县| 收藏| 淳化县| 中牟县| 清苑县| 衡南县| 天水市| 潼关县| 平武县| 达尔| 东海县|