支持GIF动画的ImageView

    网上有很多关于怎么实现android播放GIF的帖子。但是本人发现,其中多多少少都有些不如人意的地方。因此,花了几天时间,重写了ImageView以实现GIF图片的播放。在此小结一下,也希望可以给后来者一点参考。

    大致我们会在网上搜到下面四种解决方法:

    【方案一】用外部工具拆分GIF

    【方案二】用Android开源项目GifView包

    【方案三】手动解码GIF

    【方案四】用系统自带的类Movie

    本文采用方案四,继承ImageView实现GIF动画播放,支持ImageView的命名空间属性设置,支持ImageView通用接口。

 

    项目源码下载地址:

    http://download.csdn.net/detail/yarkey09/6499717


【什么是GIF】 

    GIF,就我的理解,就是很多张位图图片的集合,然后使用了某种编码方式,使得它可以体积很小但是又够清晰。由于体积小,不依赖特别的平台,所以GIF很流行。

好吧,知道的就这么多,各位看官想了解清楚的话还是请自行百度吧。不过了解了大概概念,我们就可以知道,其实让GIF播放,实际就是显示多张图片而已。

 

【方案一】用外部工具拆分GIF

    大概情况是这样:

    1,首先我们得有一张GIF (提示:选择赏心悦目的动画,可以提高学习兴趣哦^_^)

    2,然后使用工具,千刀万剐将GIF分成多张图片 => pic0.png,pic1.png,pic2.png,pic3.png,pic4.png,pic5.png

    3,接着编写android xml资源文件放在drawable目录下,说明各个帧图片以及时间duration

    4,然后代码里面使用AnimationDrawable类即可实现

    四张图片按照xml定义的时间,一张张切换,看起来就是动画了!

    动画资源文件格式是这样:(drawable/anim_gif.xml)

<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:duration="150" android:drawable="@drawable/pic0" />
<item android:duration="150" android:drawable="@drawable/pic1" />
<item android:duration="150" android:drawable="@drawable/pic2" />
<item android:duration="150" android:drawable="@drawable/pic3" />
<item android:duration="150" android:drawable="@drawable/pic4" />
<item android:duration="150" android:drawable="@drawable/pic5" />
</animation-list>

    布局文件可以是这样:

<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/anim_gif"
android:id="@+id/imgGif"></ImageView>

    代码是这样:

ImageView imageView = (ImageView) findViewById(R.id.imgGif);
Object ob = imageView.getBackground();
AnimationDrawable anim = (AnimationDrawable) ob;
anim.start();

    如果我们需要在界面上显示一个简单且固定的动画,单纯用于点缀画面,增强动感,这种方法比较方便。当然,这种方法在某些场合下显得很不灵活,不能满足要求效果,那么请继续参考后面的方法吧。

参考帖子:Android开发:教您如何让Gif动画动起来

 

【方案二】用Android开源项目GifView包

    我们同样可以在网上搜到这个开源项目的相关应用。有了这个包,我们要让GIF播放这个事情就变得非常轻松。看看它那强大的接口就知道了!使用GifView几乎就跟ImageView是一样的。方便!开源项目确实有很多代码都有非常好的学习价值,表示有空应该好好拜读一番!

// 从xml中得到GifView的句柄 
gif1 = (GifView) findViewById(R.id.gif1); 
// 设置Gif图片源 
gif1.setGifImage(R.drawable.gif1); 
// 添加监听器 
gif1.setOnClickListener(this); 
// 设置显示的大小,拉伸或者压缩 
gif1.setShowDimension(300, 300); 
// 设置加载方式:先加载后显示、边加载边显示、只显示第一帧再显示
gif1.setGifImageType(GifImageType.COVER); 

参考帖子:介绍一个Android开源项目:GifView——Android显示GIF动画

 

【方案三】手动解码GIF

    用java来解码,很多人会觉得效率比较低。但是我们目的是学习,完全可以尝试一下!当然,也可以用native代码完成解码,在java用JNI调用。

    将GIF文件解码后,我们可以得到所有想要的信息。比如Gif版本GIF87a, GIF89a等等,关键是我们可以得到几张Bitmap图片,还有各张图片的显示延续时间。其实,这里解码工作也就大致等同于上面的方案一。不同的是,我们的app可以直接播放GIF,而不需要外部的工具!

    有了各帧图片以及显示延续时间,我们便可以开始了!新建一个线程用于计时,时间一到就刷新View切换图片。这就是GIF了!

    注意一下在非主线程让View刷新,应该调用postInvalidate() 而不是invalidate()。

    下面参考帖子附有解码源程序,然后按照参考文档来阅读,很快可以看明白^_^

参考帖子: Android 解码播放GIF图像

参考文档: GIF文件格式

 

【方案四】用系统自带的类Movie

    接下来说说具体要讲的基于Movie的实现方法吧!

    使用Movie类播放GIF很简单。但是我们的目的是,继承ImageView,保留它显示图片的基本功能,尽量使得接口函数能够通用简便。这样,原先使用ImageView的项目代码只要经过少量的修改,即可支持GIF动画。根据要求,我们至少要重载下面四个通用接口以支持GIF动画:

public void setImageResource( int resID )
public void setImageURI( Uri uri )
public void setScaleType( ScaleType scaleType )
public void setPadding( int left, int top, int right, int bottom )

     说明一下:

// 我们设置了图片,那么跟ImageView一样显示出图片
setImageResource( R.drawable.pngtest ); 
// 我们这次设置了GIF动画,那么应该显示动画
setImageResource( R.drawable.giftest ); 
// 支持SD卡中的GIF动画
setImageURI( Uri.parse( "file://" + Environment.getExternalStorageDirectory().getPath() + "/sdcard_giftest.gif" ); 

    为了实现以上要求,其中遇到很多问题,我们慢慢说吧。

 

-1- Movie 是啥东西

    android.graphics.Movie 在SDK文档中没有说明,翻看源代码,发现它只是一个java壳,实际上直接调用native代码。这样导致我们没能快速学习掌握它的用法。

    不过幸亏有APIDemo!这真的是一个好东西!打开其中BitmapDecode我们可以发现代码中就用了Movie类!

    直接安装APIDemo到手机中,运行... 发现旗子飘动起来了!

    它的源代码简单清晰,大概是这样。Movie对象管理着时间轴上对应的GIF各帧图片,我们通过传入时间,便可以取出对应的帧,然后再用draw()方法,将当前的帧画到画布canvas上面。如果我们的View不停的刷新,时间不停地跑,Movie的帧就不停的切换,那么画出来的View就动起来了!

 

-2- Copy APIDemo 源码

    那么好了,按照它的代码,我们可以很快copy一份出来,然后编译安装到手机,我们想GIF似乎就这样完成了。关键代码如下。

	private static class MovieGifView extends View {

		private Movie mMovie;
		private long mMovieStart;

		public MovieGifView(Context context) {
			super(context);
			java.io.InputStream is;
			is = context.getResources().openRawResource(R.drawable.animated_gif);
			mMovie = Movie.decodeStream(is);
		}

		@Override
		protected void onDraw(Canvas canvas) {

			long now = android.os.SystemClock.uptimeMillis();
			if (mMovieStart == 0) { // first time
				mMovieStart = now;
			}
			if (mMovie != null) {
				int dur = mMovie.duration();
				if (dur == 0) {
					dur = 1000;
				}
				int relTime = (int) ((now - mMovieStart) % dur);
				mMovie.setTime(relTime);
				mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight() - mMovie.height());
				invalidate();
			}
		}
	}

    但是结果却是那么不如人意,自己写的app在一部平板(android 4.3)上运行时,GIF没有动起来,美女并没有向我眨眼!

    我第一反应便是拿去我的屌丝神机I589(I5830电信版 android 2.3) 上试试。结果反而动起来了!这么神马回事?!

    难道是android 4.3 版本太新,Movie方法不支持?后来我又找到了一部android 4.1 的手机,安装发现,GIF同样没有动!

    奇怪!头疼!

 

-3- hardwareAccelerated 惹的祸

    为什么APIDemo的代码可以,我的代码直接copy,却不行了?我翻看了很久代码,最后找到了唯一不同点,在这里 -> AndroidManifest.xml

        <activity android:hardwareAccelerated="false"
                  android:name=".graphics.BitmapDecode" android:label="Graphics/BitmapDecode">
            <intent-filter>
                <action android:name&#
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值