显示animationGIF

我想在我的应用程序中显示animationGIF图像。 正如我发现Android不支持本地生成的animationGIF。

不过,它可以使用AnimationDrawable显示animation: http : //developer.android.com/guide/topics/graphics/2d-graphics.html#frame-animation

该示例使用保存为应用程序资源框架的animation,但我需要的是直接显示animationGIF。

我的计划是将animationGIF分解为帧,并将每个帧添加为AnimationDrawable。

有谁知道如何从animationGIF中提取帧,并将它们转换成Drawable ?

Android实际上可以解码和显示animationGIF,使用android.graphics.Movie类。

这不是太多的文件,但在SDK参考 。 此外,它还用在ApiDemos中的Samples中,BitmapDecode示例中带有一些animation标志。

更新:

使用滑翔:

 dependencies { compile 'com.github.bumptech.glide:glide:4.0.0' } 

用法:

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

看文档

老回答:

这是一个优秀的图书馆:

https://github.com/koral–/android-gif-drawable

XML的用法:

 <pl.droidsonroids.gif.GifImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/src_anim" android:background="@drawable/bg_anim" /> 

JAVA的用法:

 GifImageView givImageView = (GifImageView)findViewById...; 

GifDrawable可以直接从各种来源构build:

  //asset file GifDrawable gifFromAssets = new GifDrawable( getAssets(), "anim.gif" ); //resource (drawable or raw) GifDrawable gifFromResource = new GifDrawable( getResources(), R.drawable.anim ); //byte array byte[] rawGifBytes = ... GifDrawable gifFromBytes = new GifDrawable( rawGifBytes ); //FileDescriptor FileDescriptor fd = new RandomAccessFile( "/path/anim.gif", "r" ).getFD(); GifDrawable gifFromFd = new GifDrawable( fd ); //file path GifDrawable gifFromPath = new GifDrawable( "/path/anim.gif" ); //file File gifFile = new File(getFilesDir(),"anim.gif"); GifDrawable gifFromFile = new GifDrawable(gifFile); //AssetFileDescriptor AssetFileDescriptor afd = getAssets().openFd( "anim.gif" ); GifDrawable gifFromAfd = new GifDrawable( afd ); //InputStream (it must support marking) InputStream sourceIs = ... BufferedInputStream bis = new BufferedInputStream( sourceIs, GIF_LENGTH ); GifDrawable gifFromStream = new GifDrawable( bis ); //direct ByteBuffer ByteBuffer rawGifBytes = ... GifDrawable gifFromBytes = new GifDrawable( rawGifBytes ); 

和setImageDrawable:

 givImageView.setImageDrawable(GifDrawable); 

还把(main / assets / htmls / name.gif)[用这个htmlresize]

 <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"); 

如果你想dynamic加载,你可以加载webview的数据:

 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>"; webView.loadData(yourData, "text/html; charset=utf-8", "UTF-8"); 

build议:更好地加载GIF与静态图像的更多信息检查https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

就是这样,我希望你能帮上忙。

我解决了这个问题,把它保存到手机之前,将gifanimation拆分为帧,所以我不必在Android中处理它。

然后我将每一帧下载到手机上,从中创buildDrawable,然后创buildAnimationDrawable – 非常类似于我的问题

我发现一个非常简单的方法,在这里有一个很好的和简单的工作示例

显示animation小部件

在开始工作之前,代码中有一些要做的事情

在下面的

  @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceStated); setContentView(new MYGIFView()); } } 

只是取代

 setContentView(new MYGIFView()); 

 setContentView(new MYGIFView(this)); 

和IN

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

提供您自己的gifanimation文件

  is = context.getResources().openRawResource(R.drawable.earth); movie = Movie.decodeStream(is); } 

取代第一条线

 public MYGIFView(Context context) { 

根据class级的名字…

做完这个小小的改动之后,它应该像我一样…

希望这个帮助

在Android上显示animationGIF的方法:

  • 电影类。 如上所述,这是相当错误的。
  • 的WebView。 这是非常简单的使用, 通常工作。 但是有时它开始变得不合适,而且它总是在一些你不具备的模糊设备上。 另外,你不能在任何types的列表视图中使用多个实例,因为它会把事情logging下来。 不过,你可能会认为这是主要的方法。
  • 自定义代码将gif解码为位图,并将其显示为Drawable或ImageView。 我会提到两个库:

https://github.com/koral-/android-gif-drawable-解码器是用C实现的,所以效率很高。;

https://code.google.com/p/giffiledecoder – 解码器是用Java实现的,因此使用起来更容易。 即使是大文件,效率仍然相当高。

你还会发现许多基于GifDecoder类的库。 这也是一个基于Java的解码器,但它通过将整个文件加载到内存中工作,所以它只适用于小文件。

使用ImageViewEx ,一个使用gif的库像使用ImageView一样简单。

我真的很难有Android的GIFanimation工作。 我只有以下两个工作:

  1. 的WebView
  2. 离子

WebView的工作正常,很容易,但问题是这使得视图加载速度较慢,应用程序将在一秒钟左右无响应。 我不喜欢那样。 所以我尝试了不同的方法(不工作):

  1. ImageViewEx已弃用!
  2. 毕加索没有加载animation的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"); 

没有人提到Ion或Glide库。 他们工作得很好。

与WebView相比,它更容易处理。

Glide

Android的图像加载程序库,由Google推荐。

  • 滑翔和毕加索非常相似,但是这比毕加索快得多。
  • 滑翔比毕加索消耗更less的记忆。

滑翔有什么,但毕加索没有

将GIFanimation加载到简单ImageView的function可能是Glide最有趣的function。 是的,你不能这样做与毕加索。 在这里输入图像描述 一些重要的链接 –

  1. https://github.com/bumptech/glide
  2. http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

我已经在本文提出的解决scheme中取得了成功,这个解决scheme叫做GifMovieView ,它呈现一个View ,然后可以显示或添加到一个特定的ViewGroup 。 检查指定文章的第2部分和第3部分中介绍的其他方法。

这种方法唯一的缺点是电影的抗锯齿效果不好(必须是使用“阴影”的Android Movie类的副作用)。 然后,您最好将背景设置为animationGIF中的纯色。

@PointerNull提供了很好的解决scheme,但并不完美。 它不适用于大文件的某些设备,并在ICS版本上显示带有增量帧的错误Gifanimation。 我发现没有这个错误的解决scheme。 它是与本机解码绘制的库: koral的android-gif-drawable 。

关于BitmapDecode示例的一些想法…基本上它使用了android.graphics的古老的,但没有特色的Movie类。 在最近的API版本中,您需要closures硬件加速, 如下所述 。 否则就是为我暂时停顿。

 <activity android:hardwareAccelerated="false" android:name="foo.GifActivity" android:label="The state of computer animation 2014"> </activity> 

以下是仅用GIF部分缩短的BitmapDecode示例。 你必须制作自己的Widget(View)并自己绘制。 不像ImageView那么强大。

 import android.app.Activity; import android.content.Context; import android.graphics.*; import android.os.*; import android.view.View; public class GifActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new GifView(this)); } static class GifView extends View { Movie movie; GifView(Context context) { super(context); movie = Movie.decodeStream( context.getResources().openRawResource( R.drawable.some_gif)); } @Override protected void onDraw(Canvas canvas) { if (movie != null) { movie.setTime( (int) SystemClock.uptimeMillis() % movie.duration()); movie.draw(canvas, 0, 0); invalidate(); } } } } 

另外两种方法,一种是带有WebView的ImageView,另一种可以在这个很好的教程中find。 ImageView方法使用来自Google Code的Apache许可的android-gifview 。

尝试这个,在进度条中的波纹pipe代码显示gif文件

loading_activity.xml(在Layout文件夹中)

 <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(在可绘制文件夹中)

在这里我把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(在res文件夹中)

 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); } } 

把它放到一个WebView中,它必须能够正确显示,因为默认的浏览器支持gif文件。 (Froyo +,如果我没有弄错)

我认为更好的图书馆来处理gif文件是这样的:通过koral

使用它,我很成功,这个图书馆致力于GIF的; 而毕加索和滑翔通用形象框架; 所以我认为这个库的开发者完全集中在gif文件上

使用壁画。 以下是如何做到这一点:

http://frescolib.org/docs/animations.html

以下是样本的回购:

https://github.com/facebook/fresco/tree/master/samples/animation

当心壁画不支持包装内容!

首先Android浏览器应该支持animationGIF。 如果没有,那么这是一个错误! 看看问题跟踪器。

如果您在浏览器外部显示这些animationGIF,则可能是另一回事。 要做你所要求的将需要外部库支持animationGIF的解码。

第一个端口将是看Java2D或JAI(Java高级成像)API,但如果Android Dalvik支持您的应用程序中的这些库,我会感到非常惊讶。

类似于@Leonti所说的,但更深入一点:

我所做的解决同样的问题是打开GIMP,隐藏除一个之外的所有图层,将其导出为自己的图像,然后隐藏该图层并取消隐藏下一个图层等,直到我为每个图层都有单独的资源文件。 然后,我可以将它们用作AnimationDrawable XML文件中的框架。

我解决了这个问题,通过在框架中分割gif并使用标准的androidanimation

您可以使用此链接中的GifAnimationDrawable库 – https://github.com/Hipmob/gifanimateddrawable ,并将任何gif转换为AnimationDrawable。 请享用 :)

 public class Test extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Bitmap mBitmap; private Bitmap mBitmap2; private Bitmap mBitmap3; private Bitmap mBitmap4; private Drawable mDrawable; private Movie mMovie; private long mMovieStart; // Set to false to use decodeByteArray private static final boolean DECODE_STREAM = true; private static byte[] streamToBytes(InputStream is) { ByteArrayOutputStream os = new ByteArrayOutputStream(1024); byte[] buffer = new byte[1024]; int len; try { while ((len = is.read(buffer)) >= 0) { os.write(buffer, 0, len); } } catch (java.io.IOException e) { } return os.toByteArray(); } public SampleView(Context context) { super(context); setFocusable(true); java.io.InputStream is; is = context.getResources().openRawResource(R.drawable.icon); BitmapFactory.Options opts = new BitmapFactory.Options(); Bitmap bm; opts.inJustDecodeBounds = true; bm = BitmapFactory.decodeStream(is, null, opts); // now opts.outWidth and opts.outHeight are the dimension of the // bitmap, even though bm is null opts.inJustDecodeBounds = false; // this will request the bm opts.inSampleSize = 4; // scaled down by 4 bm = BitmapFactory.decodeStream(is, null, opts); mBitmap = bm; // decode an image with transparency is = context.getResources().openRawResource(R.drawable.icon); mBitmap2 = BitmapFactory.decodeStream(is); // create a deep copy of it using getPixels() into different configs int w = mBitmap2.getWidth(); int h = mBitmap2.getHeight(); int[] pixels = new int[w * h]; mBitmap2.getPixels(pixels, 0, w, 0, 0, w, h); mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_8888); mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_4444); mDrawable = context.getResources().getDrawable(R.drawable.icon); mDrawable.setBounds(150, 20, 300, 100); is = context.getResources().openRawResource(R.drawable.animated_gif); if (DECODE_STREAM) { mMovie = Movie.decodeStream(is); } else { byte[] array = streamToBytes(is); mMovie = Movie.decodeByteArray(array, 0, array.length); } } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(0xFFCCCCCC); Paint p = new Paint(); p.setAntiAlias(true); canvas.drawBitmap(mBitmap, 10, 10, null); canvas.drawBitmap(mBitmap2, 10, 170, null); canvas.drawBitmap(mBitmap3, 110, 170, null); canvas.drawBitmap(mBitmap4, 210, 170, null); mDrawable.draw(canvas); long now = android.os.SystemClock.uptimeMillis(); if (mMovieStart == 0) { // first time mMovieStart = now; } if (mMovie != null) { int dur = mMovie.duration(); if (dur == 0) { dur = 1000; } int relTime = (int) ((now - mMovieStart) % dur); mMovie.setTime(relTime); mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight() - mMovie.height()); invalidate(); } } } } class GraphicsActivity extends Activity { // set to true to test Picture private static final boolean TEST_PICTURE = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public void setContentView(View view) { if (TEST_PICTURE) { ViewGroup vg = new PictureLayout(this); vg.addView(view); view = vg; } super.setContentView(view); } } class PictureLayout extends ViewGroup { private final Picture mPicture = new Picture(); public PictureLayout(Context context) { super(context); } public PictureLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void addView(View child) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child); } @Override public void addView(View child, int index) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index); } @Override public void addView(View child, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, params); } @Override public void addView(View child, int index, LayoutParams params) { if (getChildCount() > 1) { throw new IllegalStateException( "PictureLayout can host only one direct child"); } super.addView(child, index, params); } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int count = getChildCount(); int maxHeight = 0; int maxWidth = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { measureChild(child, widthMeasureSpec, heightMeasureSpec); } } maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); Drawable drawable = getBackground(); if (drawable != null) { maxHeight = Math.max(maxHeight, drawable.getMinimumHeight()); maxWidth = Math.max(maxWidth, drawable.getMinimumWidth()); } setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); } private void drawPict(Canvas canvas, int x, int y, int w, int h, float sx, float sy) { canvas.save(); canvas.translate(x, y); canvas.clipRect(0, 0, w, h); canvas.scale(0.5f, 0.5f); canvas.scale(sx, sy, w, h); canvas.drawPicture(mPicture); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(mPicture.beginRecording(getWidth(), getHeight())); mPicture.endRecording(); int x = getWidth() / 2; int y = getHeight() / 2; if (false) { canvas.drawPicture(mPicture); } else { drawPict(canvas, 0, 0, x, y, 1, 1); drawPict(canvas, x, 0, x, y, -1, 1); drawPict(canvas, 0, y, x, y, 1, -1); drawPict(canvas, x, y, x, y, -1, -1); } } @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { location[0] = getLeft(); location[1] = getTop(); dirty.set(0, 0, getWidth(), getHeight()); return getParent(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = super.getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final int childLeft = getPaddingLeft(); final int childTop = getPaddingTop(); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } } }