显示动态GIF

270

我想在我的应用程序中显示动画GIF图像。但很遗憾,Android不支持原生的动画GIF。

不过,Android可以使用AnimationDrawable来显示动画:

开发 > 指南 > 图像和图形 > Drawables概述

示例使用应用程序资源中保存为帧的动画,但我需要直接显示动画GIF。

我的计划是将动画GIF拆分为帧并将每个帧作为drawable添加到AnimationDrawable中。

有人知道如何从动画GIF中提取帧,并将每个帧转换为Drawable吗?


3
你的意思是在安卓中进行,还是使用外部工具从gif文件中提取帧? - Osmund
这绝对是一个 bug,请查看 IssueTracker 获取更多信息。 - Barbarossa
只是为了那些通过搜索可以显示动画GIF的应用程序而来到这里的人:QuickPic - rubo77
1
http://stackoverflow.com/questions/30338258/best-practice-of-showing-gif-in-android/34892679#34892679 - Preetam
使用Fresco来显示GIF https://github.com/facebook/fresco 我认为这是一个简单的解决方案。 - kaitian521
我正在寻找那个问题,并在此处找到了解决方案:在Android应用程序中播放GIF - Roy Doron
29个回答

193

实际上Android可以使用android.graphics.Movie类解码和显示动画GIF。

这方面的文档不是很多,但在SDK参考文档中有相关说明。此外,在ApiDemos的BitmapDecode示例中,也使用了一些动画标志。


10
这个有多稳定?我已经在我的应用程序中实现了它,在我的冰淇淋三明治设备上根本不起作用,在一个2.3模拟器上它可以工作,但是一些GIF帧会出现问题(颜色错误)。在电脑上当然是正常的。怎么回事? - Benoit Duffez
13
在后高清设备上,您应该在视图中调用setLayerType(LAYER_TYPE_SOFTWARE)。但仍然只适用于某些gif和某些设备。 - Michał Klimczak
11
谢谢!Paint p = new Paint(); p.setAntiAlias(true); setLayerType(LAYER_TYPE_SOFTWARE, p);生效了! - Chloe
2
电影类是有意不记录的 - 它很弱,也没有支持。如果你需要正确的Gif动画,最好自己实现。我在我的应用程序中使用NDK实现了它。 - Pointer Null
4
这个类在API 28级别被弃用。 建议使用AnimatedImageDrawable - Yagnesh Lashkari
显示剩余7条评论

74

更新:

使用Glide:

dependencies {
  implementation 'com.github.bumptech.glide:glide:4.9.0'
}

使用方法:

Glide.with(context).load(GIF_URI).into(new DrawableImageViewTarget(IMAGE_VIEW));

查看文档


1
现在看起来还不错,显然答案不能包括整个库,因此调用示例似乎足够。 - gaborous
@gaborous 显然在标记时代码没有被包含。 - Jan
1
如果您已经在使用NDK,我不建议使用这个库。将此库添加到gradle后,Unity模块停止工作了。 - RominaV
GlideDrawableImageViewTarget似乎不再可用。 - Ayxan Haqverdili
@FedericoDeGioannini 谢谢。已更新。 - itzhar
显示剩余2条评论

28

还可以将(main/assets/htmls/name.gif)放置在此html中,并调整其大小

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

例如在Xml文件中声明如下(main/res/layout/name.xml):[您可以定义大小,例如]

<WebView
android:layout_width="70dp"
android:layout_height="70dp"
android:id="@+id/webView"
android:layout_gravity="center_horizontal" />

在您的Activity中,在onCreate中添加下面的代码。
web = (WebView) findViewById(R.id.webView); 
web.setBackgroundColor(Color.TRANSPARENT); //for gif without background
web.loadUrl("file:///android_asset/htmls/name.html");

如果要进行动态加载,必须通过数据加载Webview:

// or "[path]/name.gif" (e.g: file:///android_asset/name.gif for resources in asset folder), and in loadDataWithBaseURL(), you don't need to set base URL, on the other hand, it's similar to loadData() method.
String gifName = "name.gif";
String yourData = "<html style=\"margin: 0;\">\n" +
        "    <body style=\"margin: 0;\">\n" +
        "    <img src=" + gifName + " style=\"width: 100%; height: 100%\" />\n" +
        "    </body>\n" +
        "    </html>";
// Important to add this attribute to webView to get resource from outside.
webView.getSettings().setAllowFileAccess(true);

// Notice: should use loadDataWithBaseURL. BaseUrl could be the base url such as the path to asset folder, or SDCard or any other path, where your images or the other media resides related to your html
webView.loadDataWithBaseURL("file:///android_asset/", yourData, "text/html", "utf-8", null);
// Or if you want to load image from SD card or where else, here is the idea.
String base = Environment.getExternalStorageDirectory().getAbsolutePath().toString();
webView.loadDataWithBaseURL(base + '/', yourData, "text/html", "utf-8", null);

建议:最好使用静态图像加载gif,了解更多信息请查看https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html 目前我们可以使用Glide https://github.com/bumptech/glide

2
如果我想从SD卡加载GIF? - Jaydev
如果您想从sdcard加载:请将“file:///android_asset/htmls/name.html”替换为您的图像uri。 - Alex Zaraos
使用这种方法,我如何动态更改gif文件的名称?我不想为我需要在我的应用程序中显示的每个gif制作一个html文件。 - scrayne
1
网页视图用于GIF?!你有考虑过性能、内存消耗和电池吗? - Duna
@Duna,那是5年前的事了,现在我们可以使用Glide作为例子。 - Alex Zaraos
使用WebView作为动画ImageView或更改TextView中的字体...对于反应感到抱歉... - Milan Jurkulak

22

我将gif动画分解成帧,然后保存到手机上,这样在Android中就不必处理它了。

然后我将每一帧下载到手机上,从中创建Drawable,再创建AnimationDrawable - 这与我的问题示例非常相似。


2
处理动画的文档方式是什么? - RichieHH

17
我发现了一个非常简单的方法,在这里有一个漂亮而简单的工作示例。

显示动画小部件

在让它工作之前,需要对代码进行一些更改。
以下是更改内容:
    @Override
    public void onCreate(Bundle savedInstanceState){    
        super.onCreate(savedInstanceStated);   
        setContentView(new MYGIFView());
    }    
}

只需要替换

setContentView(new MYGIFView());


setContentView(new MYGIFView(this));

AND IN

public GIFView(Context context) {
    super(context);

提供您自己的gif动画文件。
    is = context.getResources().openRawResource(R.drawable.earth);
    movie = Movie.decodeStream(is);
}

将第一行替换为:
public MYGIFView(Context context) {

根据课程名称...
完成这些小更改后,对我来说应该可以工作...
希望这有所帮助。

2
你尝试在哪个Android版本上运行?我尝试了Android 2.2和2.3,但返回的Movie对象为空。你有什么想法可能出了什么问题吗? - Ashwini Shahapurkar
17
请整理一下这个答案,它太随意了。 - taxeeta
2
答案有什么问题吗?我只是提供了一个链接和一些必要的修复来使它正常工作。 - Apperside

16

Glide 4.6

1. 加载gif动图

GlideApp.with(context)
            .load(R.raw.gif) // or url
            .into(imageview);

2. 获取文件对象

GlideApp.with(context)
                .asGif()
                .load(R.raw.gif) //or url
                .into(new SimpleTarget<GifDrawable>() {
                    @Override
                    public void onResourceReady(@NonNull GifDrawable resource, @Nullable Transition<? super GifDrawable> transition) {

                        resource.start();
                      //resource.setLoopCount(1);
                        imageView.setImageDrawable(resource);
                    }
                });

10

我在Android上很难让动画GIF工作,只有以下两个方法可行:

  1. WebView
  2. Ion

WebView效果还不错,而且非常简单,但问题是它会使视图加载变慢,应用程序可能会失去响应一两秒钟。我不喜欢这样。所以我尝试了不同的方法(没有成功):

  1. ImageViewEx已经过时了!
  2. picasso无法加载动画gif
  3. android-gif-drawable看起来很棒,但是它在我的项目中引起了一些奇怪的NDK问题。它导致我的本地NDK库停止工作,我无法修复它

我和Ion反复尝试之后,最终让它正常工作了,并且速度非常快 :-)

Ion.with(imgView)
  .error(R.drawable.default_image)
  .animateGif(AnimateGifMode.ANIMATE)
  .load("file:///android_asset/animated.gif");

我也在使用android-gif-drawable时遇到了与NDK相关的问题。 - RominaV
你好 @RominaV,你在Ion中使用过进度条来加载gif吗?因为我需要在加载gif时显示进度。 - patel135

10

在Android上展示动态GIF的方法:

  • Movie类。如上所述,这种方法非常容易出现错误。
  • WebView。使用起来非常简单,通常也能工作。但有时会开始表现不良,而且它总是在你没有的某些晦涩设备上出现问题。此外,您不能在任何类型的列表视图中使用多个实例,因为它会影响您的内存。尽管如此,您仍然可以将其考虑为主要方法。
  • 自定义代码将GIF解码为位图,并将它们显示为Drawable或ImageView。我会提到两个库:

https://github.com/koral--/android-gif-drawable - 该解码器是用C实现的,因此非常高效。

https://code.google.com/p/giffiledecoder - 该解码器是用Java实现的,因此更易于处理。即使在大文件的情况下,它仍然相当有效。

您还将找到许多基于GifDecoder类的库。这也是一种基于Java的解码器,但它通过将整个文件加载到内存中来工作,因此只适用于小文件。


9

谷歌在哪里推荐Glid? - Derzu
1
看这个,Android开发团队在他们的示例应用程序中使用了Glide。https://developer.android.com/samples/XYZTouristAttractions/Application/src/com.example.android.xyztouristattractions/config/GlideConfiguration.html - Shoeb Siddique
1
Glide与Picasso非常相似,但比Picasso更快。Glide消耗的内存比Picasso少。很抱歉,我对这些想法不满意,请参考此链接:https://medium.com/@multidots/glide-vs-picasso-930eed42b81d。顺便说一句,由于网络连接缓慢,我无法将构建升级到3.0.1,因此无法测试Glide 4.0;但我已经在显示gif时测试了Glide 3.5.2,它可以工作,但在大型图像上并不完美(会闪烁),这也是一个常见问题。请纠正我如果我错了。 - Nguyen Tan Dat

7
尝试以下代码,它会在进度条中显示gif文件。 loading_activity.xml(在布局文件夹中)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff" >

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/custom_loading"
        android:visibility="gone" />

</RelativeLayout>

自定义加载动画(custom_loading.xml,位于drawable文件夹中)

在这里我放置了黑色gif动画(black_gif.gif,位于drawable文件夹中),你也可以在此处放置自己的gif动画

<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/black_gif"
    android:pivotX="50%"
    android:pivotY="50%" />

LoadingActivity.java(in res folder)

public class LoadingActivity extends Activity {

    ProgressBar bar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_loading);
        bar = (ProgressBar) findViewById(R.id.progressBar);
        bar.setVisibility(View.VISIBLE);

    }

}

我看到你旋转了gif。为什么? - AlikElzin-kilaka
你如何将gif放入drawable文件夹中? - Apurva

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