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

Android 显示GIF图片实例详解

程序员文章站 2023-12-09 21:02:45
android 显示gif图片实例详解 gif图动画在android中还是比较常用的,比如像新浪微博中,有很多gif图片,而且展示非常好,所以我也想弄一个。经过我多方的搜...

android 显示gif图片实例详解

gif图动画在android中还是比较常用的,比如像新浪微博中,有很多gif图片,而且展示非常好,所以我也想弄一个。经过我多方的搜索资料和整理,终于弄出来了,其实github上有很多开源的gif的展示代码,我下载过几个,但是都不是很理想,不是我完全想要的。所以有时候就得自己学会总结,把开源的东西整理成自己的,现在无聊,也正好有朋友需要,所以现在整理了一下,留着以后备用!

废话不多说,直接上图:

Android 显示GIF图片实例详解

Android 显示GIF图片实例详解

在这里主要用的是:android中的android.graphics.movie 这个类,这是android提供给我们的一个非常方便的工具。
首先,重写控件view,自定义一个展示gif图的gifview,代码如下:

package net.loonggg.gif.view; 
 
import net.loonggg.gif.r; 
import android.annotation.suppresslint; 
import android.content.context; 
import android.content.res.typedarray; 
import android.graphics.canvas; 
import android.graphics.movie; 
import android.os.build; 
import android.util.attributeset; 
import android.view.view; 
 
public class gifview extends view { 
 
  /** 
   * 默认为1秒 
   */ 
  private static final int default_movie_duration = 1000; 
 
  private int mmovieresourceid; 
 
  private movie mmovie; 
 
  private long mmoviestart; 
 
  private int mcurrentanimationtime = 0; 
 
  private float mleft; 
 
  private float mtop; 
 
  private float mscale; 
 
  private int mmeasuredmoviewidth; 
 
  private int mmeasuredmovieheight; 
 
  private boolean mvisible = true; 
 
  private volatile boolean mpaused = false; 
 
  public gifview(context context) { 
    this(context, null); 
  } 
 
  public gifview(context context, attributeset attrs) { 
    this(context, attrs, r.styleable.customtheme_gifviewstyle); 
  } 
 
  public gifview(context context, attributeset attrs, int defstyle) { 
    super(context, attrs, defstyle); 
    setviewattributes(context, attrs, defstyle); 
  } 
 
  @suppresslint("newapi") 
  private void setviewattributes(context context, attributeset attrs, 
      int defstyle) { 
    if (build.version.sdk_int >= build.version_codes.honeycomb) { 
      setlayertype(view.layer_type_software, null); 
    } 
    // 从描述文件中读出gif的值,创建出movie实例 
    final typedarray array = context.obtainstyledattributes(attrs, 
        r.styleable.gifview, defstyle, r.style.widget_gifview); 
    mmovieresourceid = array.getresourceid(r.styleable.gifview_gif, -1); 
    mpaused = array.getboolean(r.styleable.gifview_paused, false); 
    array.recycle(); 
    if (mmovieresourceid != -1) { 
      mmovie = movie.decodestream(getresources().openrawresource( 
          mmovieresourceid)); 
    } 
  } 
 
  /** 
   * 设置gif图资源 
   * 
   * @param movieresid 
   */ 
  public void setmovieresource(int movieresid) { 
    this.mmovieresourceid = movieresid; 
    mmovie = movie.decodestream(getresources().openrawresource( 
        mmovieresourceid)); 
    requestlayout(); 
  } 
 
  public void setmovie(movie movie) { 
    this.mmovie = movie; 
    requestlayout(); 
  } 
 
  public movie getmovie() { 
    return mmovie; 
  } 
 
  public void setmovietime(int time) { 
    mcurrentanimationtime = time; 
    invalidate(); 
  } 
 
  /** 
   * 设置暂停 
   * 
   * @param paused 
   */ 
  public void setpaused(boolean paused) { 
    this.mpaused = paused; 
    if (!paused) { 
      mmoviestart = android.os.systemclock.uptimemillis() 
          - mcurrentanimationtime; 
    } 
    invalidate(); 
  } 
 
  /** 
   * 判断gif图是否停止了 
   * 
   * @return 
   */ 
  public boolean ispaused() { 
    return this.mpaused; 
  } 
 
  @override 
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { 
    if (mmovie != null) { 
      int moviewidth = mmovie.width(); 
      int movieheight = mmovie.height(); 
      int maximumwidth = measurespec.getsize(widthmeasurespec); 
      float scalew = (float) moviewidth / (float) maximumwidth; 
      mscale = 1f / scalew; 
      mmeasuredmoviewidth = maximumwidth; 
      mmeasuredmovieheight = (int) (movieheight * mscale); 
      setmeasureddimension(mmeasuredmoviewidth, mmeasuredmovieheight); 
    } else { 
      setmeasureddimension(getsuggestedminimumwidth(), 
          getsuggestedminimumheight()); 
    } 
  } 
 
  @override 
  protected void onlayout(boolean changed, int l, int t, int r, int b) { 
    super.onlayout(changed, l, t, r, b); 
    mleft = (getwidth() - mmeasuredmoviewidth) / 2f; 
    mtop = (getheight() - mmeasuredmovieheight) / 2f; 
    mvisible = getvisibility() == view.visible; 
  } 
 
  @override 
  protected void ondraw(canvas canvas) { 
    if (mmovie != null) { 
      if (!mpaused) { 
        updateanimationtime(); 
        drawmovieframe(canvas); 
        invalidateview(); 
      } else { 
        drawmovieframe(canvas); 
      } 
    } 
  } 
 
  @suppresslint("newapi") 
  private void invalidateview() { 
    if (mvisible) { 
      if (build.version.sdk_int >= build.version_codes.jelly_bean) { 
        postinvalidateonanimation(); 
      } else { 
        invalidate(); 
      } 
    } 
  } 
 
  private void updateanimationtime() { 
    long now = android.os.systemclock.uptimemillis(); 
    // 如果第一帧,记录起始时间 
    if (mmoviestart == 0) { 
      mmoviestart = now; 
    } 
    // 取出动画的时长 
    int dur = mmovie.duration(); 
    if (dur == 0) { 
      dur = default_movie_duration; 
    } 
    // 算出需要显示第几帧 
    mcurrentanimationtime = (int) ((now - mmoviestart) % dur); 
  } 
 
  private void drawmovieframe(canvas canvas) { 
    // 设置要显示的帧,绘制即可 
    mmovie.settime(mcurrentanimationtime); 
    canvas.save(canvas.matrix_save_flag); 
    canvas.scale(mscale, mscale); 
    mmovie.draw(canvas, mleft / mscale, mtop / mscale); 
    canvas.restore(); 
  } 
 
  @suppresslint("newapi") 
  @override 
  public void onscreenstatechanged(int screenstate) { 
    super.onscreenstatechanged(screenstate); 
    mvisible = screenstate == screen_state_on; 
    invalidateview(); 
  } 
 
  @suppresslint("newapi") 
  @override 
  protected void onvisibilitychanged(view changedview, int visibility) { 
    super.onvisibilitychanged(changedview, visibility); 
    mvisible = visibility == view.visible; 
    invalidateview(); 
  } 
 
  @override 
  protected void onwindowvisibilitychanged(int visibility) { 
    super.onwindowvisibilitychanged(visibility); 
    mvisible = visibility == view.visible; 
    invalidateview(); 
  } 
 
} 

movie其实管理着gif动画中的多个帧,只需要通过 settime() 一下就可以让它在draw()的时候绘出相应的那帧图像。通过当前时间与duration之间的换算关系,是很容易实现gif动起来的效果。

其次,在xml布局文件中,把这个view定义进去,代码如下:

<?xml version="1.0" encoding="utf-8"?> 
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:orientation="vertical" > 
 
  <net.loonggg.gif.view.gifview 
    android:id="@+id/gif1" 
    android:layout_width="100dp" 
    android:layout_height="100dp" 
    android:layout_gravity="center_horizontal" 
    android:enabled="false" /> 
 
  <net.loonggg.gif.view.gifview 
    android:id="@+id/gif2" 
    android:layout_width="200dp" 
    android:layout_height="200dp" 
    android:layout_gravity="center_horizontal" 
    android:enabled="false" /> 
 
</linearlayout> 

最后,在mainactivity中的使用,代码如下:

package net.loonggg.gif; 
 
import net.loonggg.gif.view.gifview; 
import android.app.activity; 
import android.os.bundle; 
 
public class gif extends activity { 
  private gifview gif1, gif2; 
 
  @override 
  public void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.main); 
    gif1 = (gifview) findviewbyid(r.id.gif1); 
    // 设置背景gif图片资源 
    gif1.setmovieresource(r.raw.kitty); 
    gif2 = (gifview) findviewbyid(r.id.gif2); 
    gif2.setmovieresource(r.raw.b); 
    // 设置暂停 
    // gif2.setpaused(true); 
 
  } 
 
} 

注意:与imageview和其他view唯一的区别在于我加了一个gif属性。

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 
  <declare-styleable name="gifview"> 
    <attr name="gif" format="reference" /> 
    <attr name="paused" format="boolean" /> 
  </declare-styleable> 
  <declare-styleable name="customtheme"> 
    <attr name="gifviewstyle" format="reference" /> 
  </declare-styleable> 
 
</resources> 

这个代码已经非常好了,使用也非常方便,其实不懂代码是什么意思也可以很好的用,只需要懂得我写注释的那几行和activity里面的那几行代码就可以了!

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!