============================================================================================
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 的源码。