如何在ImageView中显示 .gif 文件?

20

我的布局有很多ImageViews。我想在一个ImageView中显示.gif动画文件。我尝试了Yash的方法 (在Android中的ImageView中添加gif图像),但.gif文件显示在整个布局中,其他视图都消失了。

我想要全部显示。

有什么办法吗?


请展示一些代码,更好地描述它应该如何呈现(我们可以通过查看您的XML布局来理解),以及它失败的屏幕截图。 - MarsAtomic
我有解决方案,请参考此链接。https://dev59.com/UHA65IYBdhLWcg3wvhTi#23670399 - nirav kalola
可能是在Android中的ImageView中添加gif图像的重复问题。 - msangel
8个回答

17

如果您不想使用Glide,只需将以下内容添加到您的依赖项,并创建您独特的“gif”。在使用之前检查最新版本。ImageView:

implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.19'

使用最少的代码行高效运作。以下是一个例子:

<pl.droidsonroids.gif.GifImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/dancer"
        android:src="@drawable/maddancer" />

10
使用第三方依赖。
将以下依赖项添加到您的应用gradle文件中。
dependencies {
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.17'

}

然后同步您的项目。当同步完成后,转到您的布局文件并添加以下代码。
<pl.droidsonroids.gif.GifImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/gif_file"/>

这是将.gif图像显示到ImageView中最简单的方法,您可以像处理常规Android ImageView引用从这个答案那样处理。

另一种在没有添加任何依赖项到app gradle文件的情况下将.gif显示到imageview的方法。

将您的.gif文件放入res/raw文件夹中,在您的片段或活动中,然后您可以像这样在imageview中设置gif。

GifAnimationDrawable gif;
    
    try {
            gif = new 
             GifAnimationDrawable(getResources().openRawResource(R.raw.download));
            gif.setOneShot(false);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        ivGif.setImageDrawable(gif);
        gif.setVisible(true, true);
    }

1) GifAnimationDrawable.java
public class GifAnimationDrawable extends AnimationDrawable

    {
        private boolean decoded;
    
    private GifDecoder mGifDecoder;

    private Bitmap mTmpBitmap;

    private int height, width;
    
    public GifAnimationDrawable(File f) throws IOException
    {
        this(f, false);
    }
    
    public GifAnimationDrawable(InputStream is) throws IOException
    {
        this(is, false);
    }
    
    public GifAnimationDrawable(File f, boolean inline) throws IOException
    {
        this(new BufferedInputStream(new FileInputStream(f), 32768), inline);
    }
    
    public GifAnimationDrawable(InputStream is, boolean inline) throws IOException
    {
        super();
        InputStream bis = is;
        if(!BufferedInputStream.class.isInstance(bis)) bis = new BufferedInputStream(is, 32768);
        decoded = false;
        mGifDecoder = new GifDecoder();
        mGifDecoder.read(bis);
        mTmpBitmap = mGifDecoder.getFrame(0);
        android.util.Log.v("GifAnimationDrawable", "===>Lead frame: ["+width+"x"+height+"; "+mGifDecoder.getDelay(0)+";"+mGifDecoder.getLoopCount()+"]");
        height = mTmpBitmap.getHeight();
        width = mTmpBitmap.getWidth();
        addFrame(new BitmapDrawable(mTmpBitmap), mGifDecoder.getDelay(0));
        setOneShot(mGifDecoder.getLoopCount() != 0);
        setVisible(true, true);
        if(inline){
            loader.run();
        }else{
            new Thread(loader).start();
        }
    }
    
    public boolean isDecoded(){ return decoded; }
    
    private Runnable loader = new Runnable(){
        public void run() 
        {
            mGifDecoder.complete();
            int i, n = mGifDecoder.getFrameCount(), t;
            for(i=1;i<n;i++){
                mTmpBitmap = mGifDecoder.getFrame(i);
                t = mGifDecoder.getDelay(i);
                android.util.Log.v("GifAnimationDrawable", "===>Frame "+i+": "+t+"]");
                addFrame(new BitmapDrawable(mTmpBitmap), t);
            }
            decoded = true;
            mGifDecoder = null;
        }
    };
    
    public int getMinimumHeight(){ return height; }
    public int getMinimumWidth(){ return width; }
    public int getIntrinsicHeight(){ return height; }
    public int getIntrinsicWidth(){ return width; }
}
  1. GifDecoder.java

    public class GifDecoder

    {

     public static final int STATUS_OK = 0;  
     public static final int STATUS_FORMAT_ERROR = 1;
     public static final int STATUS_OPEN_ERROR = 2;  
     protected static final int MAX_STACK_SIZE = 4096;
     public static final    int MIN_DELAY                   = 100;
     public static final    int MIN_DELAY_ENFORCE_THRESHOLD = 20;
     protected InputStream in;
     protected int status;
     protected int width; // full image width
     protected int height; // full image height
     protected boolean gctFlag; // global color table used
     protected int gctSize; // size of global color table
     protected int loopCount = 1; // iterations; 0 = repeat forever
     protected int[] gct; // global color table
     protected int[] lct; // local color table
     protected int[] act; // active color table
     protected int bgIndex; // background color index
     protected int bgColor; // background color
     protected int lastBgColor; // previous bg color
     protected int pixelAspect; // pixel aspect ratio
     protected boolean lctFlag; // local color table flag
     protected boolean interlace; // interlace flag
     protected int lctSize; // local color table size
     protected int ix, iy, iw, ih; // current image rectangle
     protected int lrx, lry, lrw, lrh;
     protected Bitmap image; // current frame
     protected Bitmap lastBitmap; // previous frame
     protected byte[] block = new byte[256]; // current data block
     protected int blockSize = 0; // block size last graphic control extension info
     protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
     protected int lastDispose = 0;
     protected boolean transparency = false; // use transparent color
     protected int delay = 0; // delay in milliseconds
     protected int transIndex; // transparent color index
     // LZW decoder working arrays
     protected short[] prefix;
     protected byte[] suffix;
     protected byte[] pixelStack;
     protected byte[] pixels;
     protected Vector<GifFrame> frames; // frames read from current file
     protected int frameCount;
    
     private boolean readComplete;
    
     public GifDecoder()
     {
         readComplete = false;
     }
    
     private static class GifFrame {
         public GifFrame(Bitmap im, int del) {
             image = im;
             delay = del;
         }
    
         public Bitmap image;
         public int delay;
     }
    
     /**
      * Gets display duration for specified frame.
      *
      * @param n
      *          int index of frame
      * @return delay in milliseconds
      */
     public int getDelay(int n) {
         delay = -1;
         if ((n >= 0) && (n < frameCount)) {
             delay = frames.elementAt(n).delay;
             //meets browser compatibility standards
             if (delay < MIN_DELAY_ENFORCE_THRESHOLD) delay = MIN_DELAY;
         }
         return delay;
     }
    
     /**
      * Gets the number of frames read from file.
      *
      * @return frame count
      */
     public int getFrameCount() {
         return frameCount;
     }
    
     /**
      * Gets the first (or only) image read.
      *
      * @return BufferedBitmap containing first frame, or null if none.
      */
     public Bitmap getBitmap() {
         return getFrame(0);
     }
    
     /**
      * Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitiely.
      *
      * @return iteration count if one was specified, else 1.
      */
     public int getLoopCount() {
         return loopCount;
     }
    
     /**
      * Creates new frame image from current data (and previous frames as specified by their disposition codes).
      */
     protected void setPixels() {
         // expose destination image's pixels as int array
         int[] dest = new int[width * height];
         // fill in starting image contents based on last image's dispose code
         if (lastDispose > 0) {
             if (lastDispose == 3) {
                 // use image before last
                 int n = frameCount - 2;
                 if (n > 0) {
                     lastBitmap = getFrame(n - 1);
                 } else {
                     lastBitmap = null;
                 }
             }
             if (lastBitmap != null) {
                 lastBitmap.getPixels(dest, 0, width, 0, 0, width, height);
                 // copy pixels
                 if (lastDispose == 2) {
                     // fill last image rect area with background color
                     int c = 0;
                     if (!transparency) {
                         c = lastBgColor;
                     }
                     for (int i = 0; i < lrh; i++) {
                         int n1 = (lry + i) * width + lrx;
                         int n2 = n1 + lrw;
                         for (int k = n1; k < n2; k++) {
                             dest[k] = c;
                         }
                     }
                 }
             }
         }
         // copy each source line to the appropriate place in the destination
         int pass = 1;
         int inc = 8;
         int iline = 0;
         for (int i = 0; i < ih; i++) {
             int line = i;
             if (interlace) {
                 if (iline >= ih) {
                     pass++;
                     switch (pass) {
                     case 2:
                         iline = 4;
                         break;
                     case 3:
                         iline = 2;
                         inc = 4;
                         break;
                     case 4:
                         iline = 1;
                         inc = 2;
                         break;
                     default:
                         break;
                     }
                 }
                 line = iline;
                 iline += inc;
             }
             line += iy;
             if (line < height) {
                 int k = line * width;
                 int dx = k + ix; // start of line in dest
                 int dlim = dx + iw; // end of dest line
                 if ((k + width) < dlim) {
                     dlim = k + width; // past dest edge
                 }
                 int sx = i * iw; // start of line in source
                 while (dx < dlim) {
                     // map color and insert in destination
                     int index = ((int) pixels[sx++]) & 0xff;
                     int c = act[index];
                     if (c != 0) {
                         dest[dx] = c;
                     }
                     dx++;
                 }
             }
         }
         image = Bitmap.createBitmap(dest, width, height, Config.ARGB_4444);
     }
    
     /**
      * Gets the image contents of frame n.
      *
      * @return BufferedBitmap representation of frame, or null if n is invalid.
      */
     public Bitmap getFrame(int n) {
         if (frameCount <= 0)
             return null;
         n = n % frameCount;
         return ((GifFrame) frames.elementAt(n)).image;
     }
    
     /**
      * Reads GIF image from stream
      *
      * @param is
      *          containing GIF file.
      * @return read status code (0 = no errors)
      */
     public int read(InputStream is)
     {
         init();
         if (is != null) {
             in = is;
             readHeader();
             if (!err()) {
                 readContents();
                 if (frameCount < 0) {
                     status = STATUS_FORMAT_ERROR;
                 }
             }
         } else {
             status = STATUS_OPEN_ERROR;
         }
         readComplete = true;
         return status;
     }
    
     public void complete()
     {
         readContents();
         try {
             in.close();
         } catch (Exception e) {
         }
     }
    
     /**
      * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick.
      */
     protected void decodeBitmapData() {
         int nullCode = -1;
         int npix = iw * ih;
         int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;
         if ((pixels == null) || (pixels.length < npix)) {
             pixels = new byte[npix]; // allocate new pixel array
         }
         if (prefix == null) {
             prefix = new short[MAX_STACK_SIZE];
         }
         if (suffix == null) {
             suffix = new byte[MAX_STACK_SIZE];
         }
         if (pixelStack == null) {
             pixelStack = new byte[MAX_STACK_SIZE + 1];
         }
         // Initialize GIF data stream decoder.
         data_size = read();
         clear = 1 << data_size;
         end_of_information = clear + 1;
         available = clear + 2;
         old_code = nullCode;
         code_size = data_size + 1;
         code_mask = (1 << code_size) - 1;
         for (code = 0; code < clear; code++) {
             prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException
             suffix[code] = (byte) code;
         }
         // Decode GIF pixel stream.
         datum = bits = count = first = top = pi = bi = 0;
         for (i = 0; i < npix;) {
             if (top == 0) {
                 if (bits < code_size) {
                     // Load bytes until there are enough bits for a code.
                     if (count == 0) {
                         // Read a new data block.
                         count = readBlock();
                         if (count <= 0) {
                             break;
                         }
                         bi = 0;
                     }
                     datum += (((int) block[bi]) & 0xff) << bits;
                     bits += 8;
                     bi++;
                     count--;
                     continue;
                 }
                 // Get the next code.
                 code = datum & code_mask;
                 datum >>= code_size;
                     bits -= code_size;
                     // Interpret the code
                     if ((code > available) || (code == end_of_information)) {
                         break;
                     }
                     if (code == clear) {
                         // Reset decoder.
                         code_size = data_size + 1;
                         code_mask = (1 << code_size) - 1;
                         available = clear + 2;
                         old_code = nullCode;
                         continue;
                     }
                     if (old_code == nullCode) {
                         pixelStack[top++] = suffix[code];
                         old_code = code;
                         first = code;
                         continue;
                     }
                     in_code = code;
                     if (code == available) {
                         pixelStack[top++] = (byte) first;
                         code = old_code;
                     }
                     while (code > clear) {
                         pixelStack[top++] = suffix[code];
                         code = prefix[code];
                     }
                     first = ((int) suffix[code]) & 0xff;
                     // Add a new string to the string table,
                     if (available >= MAX_STACK_SIZE) {
                         break;
                     }
                     pixelStack[top++] = (byte) first;
                     prefix[available] = (short) old_code;
                     suffix[available] = (byte) first;
                     available++;
                     if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) {
                         code_size++;
                         code_mask += available;
                     }
                     old_code = in_code;
             }
             // Pop a pixel off the pixel stack.
             top--;
             pixels[pi++] = pixelStack[top];
             i++;
         }
         for (i = pi; i < npix; i++) {
             pixels[i] = 0; // clear missing pixels
         }
     }
    
     /**
      * Returns true if an error was encountered during reading/decoding
      */
     protected boolean err() {
         return status != STATUS_OK;
     }
    
     /**
      * Initializes or re-initializes reader
      */
     protected void init() {
         status = STATUS_OK;
         frameCount = 0;
         frames = new Vector<GifFrame>();
         gct = null;
         lct = null;
     }
    
     /**
      * Reads a single byte from the input stream.
      */
     protected int read() {
         int curByte = 0;
         try {
             curByte = in.read();
         } catch (Exception e) {
             status = STATUS_FORMAT_ERROR;
         }
         return curByte;
     }
    
     /**
      * Reads next variable length block from input.
      *
      * @return number of bytes stored in "buffer"
      */
     protected int readBlock() {
         blockSize = read();
         int n = 0;
         if (blockSize > 0) {
             try {
                 int count = 0;
                 while (n < blockSize) {
                     count = in.read(block, n, blockSize - n);
                     if (count == -1) {
                         break;
                     }
                     n += count;
                 }
             } catch (Exception e) {
                 e.printStackTrace();
             }
             if (n < blockSize) {
                 status = STATUS_FORMAT_ERROR;
             }
         }
         return n;
     }
    
     /**
      * Reads color table as 256 RGB integer values
      *
      * @param ncolors
      *          int number of colors to read
      * @return int array containing 256 colors (packed ARGB with full alpha)
      */
     protected int[] readColorTable(int ncolors) {
         int nbytes = 3 * ncolors;
         int[] tab = null;
         byte[] c = new byte[nbytes];
         int n = 0;
         try {
             n = in.read(c);
         } catch (Exception e) {
             e.printStackTrace();
         }
         if (n < nbytes) {
             status = STATUS_FORMAT_ERROR;
         } else {
             tab = new int[256]; // max size to avoid bounds checks
             int i = 0;
             int j = 0;
             while (i < ncolors) {
                 int r = ((int) c[j++]) & 0xff;
                 int g = ((int) c[j++]) & 0xff;
                 int b = ((int) c[j++]) & 0xff;
                 tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
             }
         }
         return tab;
     }
    
     /**
      * Main file parser. Reads GIF content blocks.
      */
     protected void readContents() {
         // read GIF file content blocks
         boolean done = false;
         while (!(done || err())) {
             int code = read();
             switch (code) {
             case 0x2C: // image separator
             readBitmap();
             if(!readComplete) return;
             break;
             case 0x21: // extension
                 code = read();
                 switch (code) {
                 case 0xf9: // graphics control extension
                     readGraphicControlExt();
                     break;
                 case 0xff: // application extension
                     readBlock();
                     String app = "";
                     for (int i = 0; i < 11; i++) {
                         app += (char) block[i];
                     }
                     if (app.equals("NETSCAPE2.0")) {
                         readNetscapeExt();
                     } else {
                         skip(); // don't care
                     }
                     break;
                 case 0xfe:// comment extension
                     skip();
                     break;
                 case 0x01:// plain text extension
                     skip();
                     break;
                 default: // uninteresting extension
                     skip();
                 }
                 break;
             case 0x3b: // terminator
                 done = true;
                 break;
             case 0x00: // bad byte, but keep going and see what happens break;
             default:
                 status = STATUS_FORMAT_ERROR;
             }
         }
     }
    
     /**
      * Reads Graphics Control Extension values
      */
     protected void readGraphicControlExt() {
         read(); // block size
         int packed = read(); // packed fields
         dispose = (packed & 0x1c) >> 2; // disposal method
                     if (dispose == 0) {
                         dispose = 1; // elect to keep old image if discretionary
                     }
                     transparency = (packed & 1) != 0;
                     delay = readShort() * 10; // delay in milliseconds
                     transIndex = read(); // transparent color index
                     read(); // block terminator
     }
    
     /**
      * Reads GIF file header information.
      */
     protected void readHeader() {
         String id = "";
         for (int i = 0; i < 6; i++) {
             id += (char) read();
         }
         if (!id.startsWith("GIF")) {
             status = STATUS_FORMAT_ERROR;
             return;
         }
         readLSD();
         if (gctFlag && !err()) {
             gct = readColorTable(gctSize);
             bgColor = gct[bgIndex];
         }
     }
    
     /**
      * Reads next frame image
      */
     protected void readBitmap() {
         ix = readShort(); // (sub)image position & size
         iy = readShort();
         iw = readShort();
         ih = readShort();
         int packed = read();
         lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace
         lctSize = (int) Math.pow(2, (packed & 0x07) + 1);
         // 3 - sort flag
         // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color
         // table size
         interlace = (packed & 0x40) != 0;
         if (lctFlag) {
             lct = readColorTable(lctSize); // read table
             act = lct; // make local table active
         } else {
             act = gct; // make global table active
             if (bgIndex == transIndex) {
                 bgColor = 0;
             }
         }
         int save = 0;
         if (transparency) {
             save = act[transIndex];
             act[transIndex] = 0; // set transparent color if specified
         }
         if (act == null) {
             status = STATUS_FORMAT_ERROR; // no color table defined
         }
         if (err()) {
             return;
         }
         decodeBitmapData(); // decode pixel data
         skip();
         if (err()) {
             return;
         }
         frameCount++;
         // create new image to receive frame data
         image = Bitmap.createBitmap(width, height, Config.ARGB_4444);
         setPixels(); // transfer pixel data to image
         frames.addElement(new GifFrame(image, delay)); // add image to frame
         // list
         if (transparency) {
             act[transIndex] = save;
         }
         resetFrame();
     }
    
     /**
      * Reads Logical Screen Descriptor
      */
     protected void readLSD() {
         // logical screen size
         width = readShort();
         height = readShort();
         // packed fields
         int packed = read();
         gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
         // 2-4 : color resolution
         // 5 : gct sort flag
         gctSize = 2 << (packed & 7); // 6-8 : gct size
         bgIndex = read(); // background color index
         pixelAspect = read(); // pixel aspect ratio
     }
    
     /**
      * Reads Netscape extenstion to obtain iteration count
      */
     protected void readNetscapeExt() {
         do {
             readBlock();
             if (block[0] == 1) {
                 // loop count sub-block
                 int b1 = ((int) block[1]) & 0xff;
                 int b2 = ((int) block[2]) & 0xff;
                 loopCount = (b2 << 8) | b1;
             }
         } while ((blockSize > 0) && !err());
     }
    
     /**
      * Reads next 16-bit value, LSB first
      */
     protected int readShort() {
         // read 16-bit value, LSB first
         return read() | (read() << 8);
     }
    
     /**
      * Resets frame state for reading next image.
      */
     protected void resetFrame() {
         lastDispose = dispose;
         lrx = ix;
         lry = iy;
         lrw = iw;
         lrh = ih;
         lastBitmap = image;
         lastBgColor = bgColor;
         dispose = 0;
         transparency = false;
         delay = 0;
         lct = null;
     }
    
     /**
      * Skips variable length blocks up to and including next zero length block.
      */
     protected void skip() {
         do {
             readBlock();
         } while ((blockSize > 0) && !err());
     }
    

    }

你可以从以下链接下载这个类:https://github.com/Hipmob/gifanimateddrawable/blob/master/src/com/hipmob/gifanimationdrawable/GifAnimationDrawable.java 404 Not Found https://gist.github.com/devunwired/4479231 404 Not Found 如果以上任何链接无法打开,你可以从下面的链接找到这个类。
希望这能节省某人的时间,因为我很欣赏https://dev59.com/z2w15IYBdhLWcg3wkMjz#11736861,但我想在ImageView中显示它。
此外,如果链接不可用,你也可以从Github上找到这个类。如果你发现任何问题,请在评论中留言,我会尽力帮助 :) 编辑:2019年12月12日 另一种在自定义图片视图中加载GIF的方法是使用这个库library

6
老兄,这个应该放在Github上,它的效果比Glide和Fresco都要好 - 我能得到你的许可来为此创建一个小的第三方库吗? - Royi Benyossef
1
@royiby 如果你已经创建了库,请分享链接。 - Sandeep Kaul
@Ajay Pandya,请问您能否分享一下那两个类的下载链接,由于 Dropbox 链接无法使用。 - Yograj Shinde
@Ajay GifAnimationDrawable文件不存在,请帮忙。 - curiousMind
请查看我回答中提供的链接。 - Ajay Pandya

5

Glide 是最好的解决方案。只需使用以下代码即可。

String gifUrl = "http://part/to/your/gifFile.gif";
Glide  
.with( context )
.load( gifUrl )
.into( imageViewGif );

5

或者您可以简单地将WebView添加到您的xml中,并在webview中加载gif图像。 您不需要做任何其他操作。 图片将在webview内自动循环。


5

在安卓设备中展示GIF图片的最佳和最简单的解决方案,如下:

  • Open build.gradle (Module: app)
  • put in dependencies: compile 'pl.droidsonroids.gif:android-gif-drawable:1.1.+'
  • Open layout folder and put this code where you want to display GIF image: e-g activity_main.xml

     <pl.droidsonroids.gif.GifImageView
          android:layout_width="150dp"
          android:layout_height="wrap_content"
          android:src="@drawable/your_gif_file_name"/>
    
  • android:src="@drawable/your_gif_file_name", Replace 'your_gif_file_name' with your desired gif image file


3

使用Glide(https://github.com/bumptech/glide):

GlideDrawableImageViewTarget imageViewTarget = new GlideDrawableImageViewTarget(imageview);

        Glide.with(this).load(R.raw.mygif).into(imageViewTarget);

3

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接