============================================================================================

Android播放Gif的方案有几种,比如使用webview解帧启用线程播放等,这里使用的是Movie这个类来完成

我们查看SDK目录下的例子,google给了我们一个例子,具体位置在SDK_HOME/samples/android-17/ApiDemos/src/com/example/android/apis/graphics/BitmapDecode.java ,这里有如何去使用这篇文章的目的是要做一个通用的GIF播放的自定义控件,这里会介绍如果自己构建这个简单的控件,然后一步一步进行一些必要的扩展,实现代码使用和xml配置使用的过程

需要自定义控件,那么我们就需要创建一个继承自View的类GifView,并且重写默认的几个构造方法



package                   com.ilovn.app.test.dynamicface;                 
                  import                   android.content.Context;                 
                  import                   android.graphics.Movie;                 
                  import                   android.view.View;                 
                  public                   class                   GifView                   extends                   View {                 
                  private                   Movie mMovie;                 
                  private                   long                   movieStart;                 
                  public                   GifView(Context context) {                 
                  super                  (context);                 
                  initializeView();                 
                  }                 
                  public                   GifView(Context context, AttributeSet attrs,                   int                   defStyle) {                 
                  super                  (context, attrs, defStyle);                 
                  initializeView();                 
                  }                 
                  public                   GifView(Context context, AttributeSet attrs) {                 
                  super                  (context, attrs);                 
                  initializeView();                 
                  }                 
                  /**                 
                  * 初始化设置                 
                  */                 
                  private                   void                   initializeView() {                 
                  //TODO 在这里做一些初始化工作,这里代码先不写,我们需要扩展                 
                  }                 
                  }



我们需要使用OnDraw(Canvas)还绘制View,但在此之前,我们必须让Movie对象知道怎么播放,需要播放哪部分,要做到这一点,我们需要一个独立的变量movieStart长型的,这里我们分配SystemClock.uptimeMillis()值通过获取整个GIF的播放时间,计算应该播放gif的哪一帧,通过mMovie.setTime()



@Override                 
                  protected                   void                   onDraw(Canvas canvas) {                 
                  canvas.drawColor(Color.TRANSPARENT);                 
                  super                  .onDraw(canvas);                 
                  long                   now = android.os.SystemClock.uptimeMillis();                 
                  if                   (movieStart ==                   0                  ) {                 
                  movieStart = now;                 
                  }                 
                  int                   d = mMovie.duration();                 
                  if                   (d <=                   0                  ) {                 
                  d =                   1000                  ;                 
                  }                 
                  if                   (mMovie !=                   null                  ) {                 
                  int                   relTime = (                  int                  ) ((now - movieStart) % d);                 
                  mMovie.setTime(relTime);                 
                  mMovie.draw(canvas, (getWidth() - mMovie.width()) /                   2                  ,                 
                  (getHeight() - mMovie.height()) /                   2                  );                 
                  this                  .invalidate();                 
                  }                 
                  }



到这里还不够,我们还需要做的是告诉GifView应该显示的资源来源是什么,根据我们平时使用的提供的View可知,我们应该至少提供java代码指定资源和xml配置资源两种形式

首先是使用xml配置的资源,我们需要自定义一个在xml中参数来指定资源,我们在values/attrs.xml加入



<                  declare-styleable                   name                  =                  "GIFView"                  >                 
                  <                  attr                   name                  =                  "src"                   format                  =                  "integer"                   />                 
                  </                  declare-styleable                  >



使用了自定义的参数后,我们在xml中配置的时候,需要指定一个前缀,类似:
xmlns:gif="http://schemas.android.com/apk/res/<your app packagename 如:com.ilovn.app.test.dynamicface>"
然后在GifView的配置中这样使用:



<                  com.ilovn.app.test.dynamicface.GifView                 
                  android:id                  =                  "@+id/imageview_smile"                 
                  android:layout_width                  =                  "wrap_content"                 
                  android:layout_height                  =                  "wrap_content"                 
                  android:layout_below                  =                  "@+id/gridview"                 
                  android:layout_gravity                  =                  "center"                 
                  android:scaleType                  =                  "center"                 
                  gif:src                  =                  "@drawable/bb45"                   />



接下来在GifView里面,初始化的时候要处理:



private                   int                   gifResource;                 
                  /**                 
                  * 初始化设置                 
                  */                 
                  private                   void                   initializeView() {                 
                  if                   (gifResource !=                   0                  ) {                 
                  InputStream is = getContext().getResources().openRawResource(                 
                  gifResource);                 
                  byte                  [] array = streamToBytes(is);                 
                  mMovie = Movie.decodeByteArray(array,                   0                  , array.length);                 
                  movieStart =                   0                  ;                 
                  this                  .invalidate();                 
                  }                 
                  }



同时提供java代码中的调用设置资源ID的方法:



/**                 
                  * 设置GIF资源ID                 
                  *                 
                  * @param id                 
                  */                 
                  public                   void                   setGIFResource(                  int                   id) {                 
                  this                  .gifResource = id;                 
                  initializeView();                 
                  }



为了兼顾两种模式,我们需要提供是否使用xml配置还是java配置:



private                   boolean                   setAttrs(AttributeSet attrs) {                 
                  boolean                   f =                   false                  ;                 
                  if                   (attrs !=                   null                  ) {                 
                  TypedArray ta = getContext().obtainStyledAttributes(attrs,                 
                  R.styleable.GIFView);                 
                  int                   taCount = ta.length();                 
                  for                   (                  int                   i =                   0                  ; i < taCount; i++) {                 
                  if                   (R.styleable.GIFView_src == ta.getIndex(i)) {                 
                  int                   id = ta.getResourceId(R.styleable.GIFView_src,                   0                  );                 
                  if                   (id !=                   0                  ) {                 
                  setGIFResource(id);                 
                  f =                   true                  ;                 
                  }                 
                  }                 
                  }                 
                  ta.recycle();                 
                  }                 
                  return                   f;                 
                  }



在初始化的时候进行判断:



public                   GifView(Context context) {                 
                  super                  (context);                 
                  initializeView();                 
                  }                 
                  public                   GifView(Context context, AttributeSet attrs,                   int                   defStyle) {                 
                  super                  (context, attrs, defStyle);                 
                  if                   (!setAttrs(attrs)) {                 
                  initializeView();                 
                  }                 
                  }                 
                  public                   GifView(Context context, AttributeSet attrs) {                 
                  super                  (context, attrs);                 
                  if                   (!setAttrs(attrs)) {                 
                  initializeView();                 
                  }                 
                  }



这样就提供了较为方便的设定gif资源,但是,实际在java代码中,我们可能更多的是指定其他资源类型,而不是资源ID,那么我们应该提供更多的方法支持:



/**                 
                  * 设置GIF资源数据                 
                  *                 
                  * @param bytes                 
                  */                 
                  public                   void                   setGIFResource(                  byte                  [] bytes) {                 
                  if                   (bytes ==                   null                   || bytes.length <=                   0                  ) {                 
                  return                  ;                 
                  }                 
                  mMovie = Movie.decodeByteArray(bytes,                   0                  , bytes.length);                 
                  movieStart =                   0                  ;                 
                  this                  .invalidate();                 
                  }                 
                  /**                 
                  * 设置GIF资源数据                 
                  *                 
                  * @param is                 
                  */                 
                  public                   void                   setGIFResource(InputStream is) {                 
                  if                   (is ==                   null                  ) {                 
                  return                  ;                 
                  }                 
                  byte                  [] array = streamToBytes(is);                 
                  mMovie = Movie.decodeByteArray(array,                   0                  , array.length);                 
                  movieStart =                   0                  ;                 
                  this                  .invalidate();                 
                  }                 
                  /**                 
                  * 设置GIF资源图片                 
                  *                 
                  * @param bitmap                 
                  */                 
                  public                   void                   setGIFResource(Bitmap bitmap) {                 
                  if                   (bitmap ==                   null                  ) {                 
                  return                  ;                 
                  }                 
                  ByteArrayOutputStream bos =                   new                   ByteArrayOutputStream();                 
                  bitmap.compress(CompressFormat.PNG,                   0                   /* ignored for PNG */                  , bos);                 
                  byte                  [] bitmapdata = bos.toByteArray();                 
                  mMovie = Movie.decodeByteArray(bitmapdata,                   0                  , bitmapdata.length);                 
                  movieStart =                   0                  ;                 
                  this                  .invalidate();                 
                  }



这样就算是完成了一个比较完整的GifView了附上GivView 的源码