Android自定义控件播放GIF动画

转自:http://www.ilovn.com/topic/android-custom-control-play-gif-animation/

谢谢原作者

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

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

 
 
 
 
 
posted @ 2013-01-31 00:53  __木头鱼__  阅读(610)  评论(0编辑  收藏  举报