Android:如何在给定网址的情况下显示大型动画 gif?

Posted

技术标签:

【中文标题】Android:如何在给定网址的情况下显示大型动画 gif?【英文标题】:Android: How do a display a large animated gif given a url? 【发布时间】:2010-10-23 00:46:26 【问题描述】:

假设我有大型动画 gif 的 URL,并且我想制作一个类似于 youtube 的活动,以流式方式显示动画。我该怎么做

    图像中的流? 让它与实际动画一起显示?

我知道ImageView 不是答案,因为它只显示第一帧。

一个好处是可以访问它的缓冲状态,这样我也可以同步流声音——这是YTMND查看器应用程序的一部分。虽然我可以创建一个将公共 gif 文件转码为更好格式的服务,但我希望该应用能够在没有额外依赖项的情况下运行。

【问题讨论】:

你为什么使用巨型动画 gif 而不是 MP4? 不知何故,巨型动画 gif 必须成为 YTMND 上的事物。正是因为它们使用起来不愉快,现有的浏览器不支持它们,因此需要专门的查看应用程序。 有例子developer.android.com/resources/samples/ApiDemos/src/com/… 【参考方案1】:

你试过BitmapDecode吗?

API Demos 中有一个例子here。

【讨论】:

我之前在尝试ImageView 时使用了BitmapDecode,但是我没有考虑过使用Movie 并直接绘制到Canvas。我会调查的。 好的,我现在可以使用它了,但 BitmapDecode 根本不涉及。【参考方案2】:

解决方案的一般草图是使用自定义View 绘制请求Movie 定期将自己绘制到Canvas

第一步是构建Movie 实例。有一个名为decodeStream 的工厂可以在给定InputStream 的情况下制作电影,但使用来自UrlConnection 的流是不够的。如果你尝试这个,当电影加载器尝试在流上调用reset 时,你会得到一个IOException。不幸的是,黑客是使用单独的BufferedInputStream 和手动设置的mark 来告诉它保存足够的数据以保证reset 不会失败。幸运的是,URLConnection 可以告诉我们需要多少数据。我说这种 hack 很不幸,因为它实际上需要将整个图像缓存在内存中(这对于桌面应用程序来说没有问题,但在内存受限的移动设备上却是一个严重的问题)。

这是Movie 设置代码的片段:

URL url = new URL(gifSource);
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bis.mark(conn.getContentLength());
Movie movie = Movie.decodeStream(bis);
bis.close();

接下来,您需要创建一个显示此Movie 的视图。带有自定义onDrawView 的子类可以解决问题(假设它可以访问您使用之前的代码创建的Movie)。

@Override protected void onDraw(Canvas canvas) 
    if(movie != null) 
        long now = android.os.SystemClock.uptimeMillis();
        int dur = Math.max(movie.duration(), 1); // is it really animated?
        int pos = (int)(now % dur);
        movie.setTime(pos);
        movie.draw(canvas, x, y);
    

视图不会在没有帮助的情况下触发自身重绘,在onDraw 末尾盲目调用invalidate() 只是一种能源浪费。在另一个线程(可能是您用来下载图像数据的线程)中,您可以向主线程发布消息,要求以稳定(但不是疯狂)的速度使视图失效。

Handler handler = new Handler();
new Thread() 
    @Override public void run() 
        // ... setup the movie (using the code from above)
        // ... create and display the custom view, passing the movie

        while(!Thread.currentThread().isInterrupted()) 
            handler.post(new Runnable() 
                public void run()
                    view.invalidate();
                
            );
            try 
                Thread.sleep(50); // yields 20 fps
             catch (InterruptedException e) 
                Thread.currentThread().interrupt();
            
        
    
.start();

一个非常好的解决方案应该有各种甜蜜的进度条和错误检查,但核心在这里。

【讨论】:

这在 android 版本更大的 1.5 中仍然有效吗?请参阅***.com/questions/1383246/… 了解更多信息...【参考方案3】:

也许 AnimationDrawable 对你有用?编辑:如果你想从像这篇文章这样的 URL 加载,则不是。对不起

http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

根据 GIF 的复杂性,即如果它是一个简单的加载/进度指示器,您可以将 GIF 分开,分别保存每个图像并使用 Android 框架的 AnimationDrawable。

对于简单的进度条,这可能不太容易出错,甚至可能更高效。

【讨论】:

【参考方案4】:

Glide 证明了只需一行代码即可实现这一目标的最简单有效的方法:-

Glide.with(getApplicationContext())
            .load(Uri.parse("https://media1.giphy.com/media/5ziaphcUWGKPu/200.gif"))
            .asGif().placeholder(R.drawable.ic_launcher).crossFade()
            .into(imageView);

结果在这里:-

Gif 取自这里http://giphy.com/search/big-gif/3

从这里添加 jar :- https://github.com/bumptech/glide/releases

【讨论】:

以上是关于Android:如何在给定网址的情况下显示大型动画 gif?的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView 动画问题 Android Kotlin

故事板 - 如何在没有动画和显示屏幕的情况下自动执行转场

如何在没有动画的情况下弹出到视图控制器

Android动画 三种动画

Android 使用圆形揭露动画巧妙地隐藏或显示View

Android 使用圆形揭露动画巧妙地隐藏或显示View