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()。
@Overrideprotected 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.GifViewandroid: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 的源码。
浙公网安备 33010602011771号