Display Animated GIF

Viewed 425577

I want to display animated GIF images in my aplication. As I found out the hard way Android doesn't support animated GIF natively.

However it can display animations using AnimationDrawable:

Develop > Guides > Images & Graphics > Drawables Overview

The example uses animation saved as frames in application resources but what I need is to display animated gif directly.

My plan is to break animated GIF to frames and add each frame as drawable to AnimationDrawable.

Does anyone know how to extract frames from animated GIF and convert each of them into Drawable?

29 Answers

For only android API (Android Pie)28 and +

use AnimatedImageDrawable as

// ImageView from layout
val ima : ImageView = findViewById(R.id.img_gif)
// create AnimatedDrawable 
val decodedAnimation = ImageDecoder.decodeDrawable(
        // create ImageDecoder.Source object
        ImageDecoder.createSource(resources, R.drawable.tenor))
// set the drawble as image source of ImageView
ima.setImageDrawable(decodedAnimation)
// play the animation
(decodedAnimation as? AnimatedImageDrawable)?.start()

XML code, add a ImageView

<ImageView
    android:id="@+id/img_gif"
    android:background="@drawable/ic_launcher_background" <!--Default background-->
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    android:layout_width="200dp"
    android:layout_height="200dp" />

AnimatedImageDrawable is a child of Drawable and created by ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawable which further required the instance of ImageDecoder.Source created by ImageDecoder.createSource.

ImageDecoder.createSource can only take source as a name, ByteBuffer, File, resourceId, URI, ContentResolver to create source object and uses it to create AnimatedImageDrawable as Drawable (polymorphic call)

static ImageDecoder.Source  createSource(AssetManager assets, String fileName)
static ImageDecoder.Source  createSource(ByteBuffer buffer)
static ImageDecoder.Source  createSource(File file)
static ImageDecoder.Source  createSource(Resources res, int resId)
static ImageDecoder.Source  createSource(ContentResolver cr, Uri uri)

Note: You can also create Bitmap using ImageDecoder#decodeBitmap.

Output:

AnimatedDrawable also supports resizing, frame and color manipulation

There are two options to load animated gifs into our Android apps

1)Using Glide to load the gif into an ImageView.

    String urlGif = "https://cdn.dribbble.com/users/263558/screenshots/1337078/dvsd.gif";
    //add Glide implementation into the build.gradle file.
    ImageView imageView = (ImageView)findViewById(R.id.imageView);
    Uri uri = Uri.parse(urlGif);
    Glide.with(getApplicationContext()).load(uri).into(imageView);

2) Using an html to load the gif into a WebView

Create the html with the address to the .gif file:

<html style="margin: 0;">
<body style="margin: 0;">
<img src="https://..../myimage.gif" style="width: 100%; height: 100%" />
</body>
</html>

store this file into the assets directory:

enter image description here

The load this html into the WebView of your application:

    WebView webView =  (WebView)findViewById(R.id.webView);
    webView = (WebView) findViewById(R.id.webView);
    webView.loadUrl("file:///android_asset/html/webpage_gif.html");

Heres is a complete example of this two options.

enter image description here

Just wanted to add that the Movie class is now deprecated.

This class was deprecated in API level P.

It is recommended to use this

AnimatedImageDrawable

Drawable for drawing animated images (like GIF).

Similar to what @Leonti said, but with a little more depth:

What I did to solve the same problem was open up GIMP, hide all layers except for one, export it as its own image, and then hide that layer and unhide the next one, etc., until I had individual resource files for each one. Then I could use them as frames in the AnimationDrawable XML file.

Easiest way - Can be consider the below code

We can take advantage of Imageview setImageResource , refer below code for the same.

The below code can be used to show the image like gif incase if you have the multiple split image of gif. Just split the gif into individual png from a online tool and put image in the drawable like the below order

image_1.png, image_2.png, etc.

Have the handler to change the image dynamically.

int imagePosition = 1;
    Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            public void run() {
                updateImage();
            }
        };




    public void updateImage() {

                appInstance.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        int resId = getResources().getIdentifier("image_" + imagePosition, "drawable", appInstance.getPackageName());
                        gifImageViewDummy.setImageResource(resId);
                        imagePosition++;
    //Consider you have 30 image for the anim
                        if (imagePosition == 30) {
//this make animation play only once
                            handler.removeCallbacks(runnable);

                        } else {
    //You can define your own time based on the animation
                            handler.postDelayed(runnable, 50);
                        }

//to make animation to continue use below code and remove above if else
// if (imagePosition == 30)
//imagePosition = 1;
// handler.postDelayed(runnable, 50);
// 
                    }
                });
              }

If you want to use Glide for loading gif:

Glide.with(this)
        .asGif()
        .load(R.raw.onboarding_layers) //Your gif resource
        .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE))
        .listener(new RequestListener<GifDrawable>() {
            @Override
            public boolean onLoadFailed(@Nullable @org.jetbrains.annotations.Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
                resource.setLoopCount(1);
                return false;
            }
        })
        .into((ImageView) view.findViewById(R.id.layer_icons));

To save resources there is glide library for. Have no idea why to use anything else, especialy webview to show image only. Glide is perfect and easy library that prepares animated drawable from gif and put it directly to imageview. The logic of gifdrawable handle animation itself. Gif have lzw ziped raw rgb data of an animation inside. There is no reason for complicated usage of webview and manage more files to show just a gif file in app.

Related