欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现可播放GIF动画的ImageView

程序员文章站 2024-03-07 11:24:45
android的原生控件并不支持播放gif格式的图片。我们都知道,在android中如果想要显示一张图片,可以借助imageview来完成,但是如果将一张gif图片设置到i...

android的原生控件并不支持播放gif格式的图片。我们都知道,在android中如果想要显示一张图片,可以借助imageview来完成,但是如果将一张gif图片设置到imageview里,它只会显示这张图片的第一帧,不会产生任何的动画效果。今天我们来编写一个自定义的增强型imageview(继承imageview),可以播放gif格式的图片,暂且叫做gifimageview吧。

1.自定义属性

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 <declare-styleable name="gifimageview"> 
  <attr name="auto_play" format="boolean"></attr> 
 </declare-styleable> 
</resources>

 2.自定义view中获取属性值

 private movie mmovie;//播放动画需要用到的,系统类
 private int mimagewidth;//动画的imageview的宽度
 private int mimageheight;//动画imageview的高度
 private long mmoviestart = 0;// 播放开始
 private boolean isautoplay;//是否自动播放
 private bitmap mstartplay;//开始按钮
 private boolean isplaying=false;//记录是否正在播放
 private float mscale;//图片的缩放比
 private int mmeasuredgifwidth;//缩放后图片宽
 private int mmeasuredgifheight;//缩放后图片高
 ...

 private void init(context context, attributeset attrs) {
 typedarray attributes = context.obtainstyledattributes(attrs,r.styleable.gifimageview);
 // 通过反射拿布局中src的资源id,所以gif文件需要放在布局的src中
 int resourceid = getresourceid(attributes, context, attrs);
 if (resourceid != 0) {
  // 说明是gif动画
  // 1.将resourcesid变成流
  // 2.用move来decode解析流
  // 3.获得bitmap的长宽
  inputstream is = getresources().openrawresource(resourceid);
  mmovie = movie.decodestream(is);
  if (mmovie != null) {
  bitmap bitmap = bitmapfactory.decodestream(is);
  mimagewidth = bitmap.getwidth();
  mimageheight = bitmap.getheight();
  // 用完释放
  bitmap.recycle();
  // 获得是否允许自动播放,如果不允许自动播放,则初始化播放按钮
  isautoplay = attributes.getboolean(r.styleable.gifimageview_auto_play, false);
  if (!isautoplay) {
   mstartplay = bitmapfactory.decoderesource(getresources(),r.drawable.start_play);
   setonclicklistener(this);
  }  
  }
 }
 //回收资源
 attributes.recycle();
 }

 /**
 * 通过反射拿布局中src的资源id
 * 
 * @param attrs
 * @param context
 * @param attributes
 */
 private int getresourceid(typedarray attributes, context context, attributeset attrs) {
 try {
  field filed = typedarray.class.getdeclaredfield("mvalue");
  filed.setaccessible(true);
  typedvalue typevalue = (typedvalue) filed.get(attributes);
  return typevalue.resourceid;
 } catch (exception e) {
  e.printstacktrace();
 }
 }
 return 0;
}

3.重写onmesure()

 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
 super.onmeasure(widthmeasurespec, heightmeasurespec);
 if (mmovie != null) {
  /*
   * calculate horizontal scaling
   */
  float scalew = 1f;
  int measuremodewidth = measurespec.getmode(widthmeasurespec);
  if (measuremodewidth != measurespec.unspecified) {
   int maximumwidth = measurespec.getsize(widthmeasurespec);
   scalew = (float) mimagewidth / (float) maximumwidth;
  }
  /*
   * calculate vertical scaling
   */
  float scaleh = 1f;
  int measuremodeheight = measurespec.getmode(heightmeasurespec);
  if (measuremodeheight != measurespec.unspecified) {
   int maximumheight = measurespec.getsize(heightmeasurespec);
   scaleh = (float) mimageheight / (float) maximumheight;
  }
  /*
   * calculate overall scale
   */
  mscale = 1f / math.max(scaleh, scalew);
  mmeasuredgifwidth = (int) (mimagewidth * mscale);
  mmeasuredgifheight = (int) (mimageheight * mscale);
  setmeasureddimension(mmeasuredgifwidth, mmeasuredgifheight);
 }
 }

4.重写ondraw()

 @override
 protected void ondraw(canvas canvas) {
 if (mmovie == null) {
  // mmovie等于null,说明是张普通的图片,则直接调用父类的ondraw()方法
  super.ondraw(canvas);
 } else {
  // mmovie不等于null,说明是张gif图片
  if (isautoplay) {
  // 如果允许自动播放,就播放
  playmovie(canvas);
  invalidate();
  } else {
  // 不允许自动播放的话
  // 1.判断是否正在播放
  // 2.获得第一帧的图像
  // 3.然后添加播放按钮
  if (isplaying) {
   // 如果正在播放就playmoive继续播放
   if (playmovie(canvas)) {
   isplaying = false;
   }
   invalidate();
  } else {
   // 第一帧
   mmovie.settime(0);
   canvas.save(canvas.matrix_save_flag);
   canvas.scale(mscale, mscale);
   mmovie.draw(canvas, 0, 0);// 画
   canvas.restore();
   // 绘制开始按钮
   int offsetw = (mmeasuredgifwidth - mstartplay.getwidth()) / 2;
   int offseth = (mmeasuredgifheight - mstartplay.getheight()) / 2;
   canvas.drawbitmap(mstartplay, offsetw, offseth, null);
  }
  }
 }
 }

 /**
 * 播放gif动画
 * 
 * @param canvas
 */
 private boolean playmovie(canvas canvas) {
 // 1.获取播放的时间
 // 2.如果开始start=0,则认为是开始
 // 3.记录播放的时间
 // 4.设置进度
 // 5.画动画
 // 6.如果时间大于了播放的时间,则证明结束
 long now = systemclock.uptimemillis();
 if (mmoviestart == 0) {
  mmoviestart = now;
 }
 int duration = mmovie.duration();
 if (duration == 0) {
  duration = 1000;
 }
 //记录gif播放了多少时间
 int reltime = (int) ((now - mmoviestart) % duration);
 mmovie.settime(reltime);// 设置时间
 canvas.save(canvas.matrix_save_flag);
 canvas.scale(mscale, mscale);
 mmovie.draw(canvas, 0, 0);// 画
 canvas.restore();
 if ((now - mmoviestart) >= duration) {
  // 结束
  mmoviestart = 0;
  return true;
 }
 return false;
 }

5.添加点击事件

 @override
 public void onclick(view v) {
 if(v.getid()==getid()){
  isplaying=true;
  invalidate();
 }
 }

还有一点需要注意,有些4.0以上系统的手机启动了硬件加速功能之后会导致gif动画播放不出来,因此我们需要在androidmanifest.xml中去禁用硬件加速功能,可以通过指定android:hardwareaccelerated=false来完成。

--------------------------------------------------------------------------------

现在我们来看看运行后效果如何吧,
布局文件:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 xmlns:attr="http://schemas.android.com/apk/res/com.hx.gifimageview"
 android:id="@+id/container"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

 <com.hx.gifimageview.gifimageview
  android:layout_width="150dip"
  android:layout_height="150dip"
  android:layout_margin="10dp"
  android:src="@drawable/shulan"
  attr:auto_play="false" />

 <com.hx.gifimageview.gifimageview
  android:layout_width="150dip"
  android:layout_height="150dip"
  android:layout_margin="10dp"
  android:src="@drawable/shulan"
  attr:auto_play="true" />

 <com.hx.gifimageview.gifimageview
  android:layout_width="150dip"
  android:layout_height="150dip"
  android:layout_margin="10dp"
  android:src="@drawable/jingtai"
  attr:auto_play="true" />
</linearlayout>

 Android实现可播放GIF动画的ImageView

图一的auto_play属性为false,会显示第一帧和一个播放按钮,点击后gif图片会自动运行。
图二的auto_play属性为true,会自动循环播放gif。
图三我们给的资源是静态图片,因为自定义view继承imageview,所以具备imageview所有特性,因此也能显示静态图片。

源码下载:http://xiazai.jb51.net/201609/yuanma/gifimageview(jb51.net).rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。