Mostrar GIF animado

261

Quiero mostrar imágenes animadas GIF en mi aplicación. Como descubrí de la manera difícil, Android no admite GIF animado de forma nativa.

Sin embargo, puede mostrar animaciones usando AnimationDrawable :

Desarrollar> Guías> Imágenes y gráficos> Descripción general de Drawables

El ejemplo usa animación guardada como cuadros en los recursos de la aplicación, pero lo que necesito es mostrar gif animados directamente.

Mi plan es dividir el GIF animado en cuadros y agregar cada cuadro como dibujable a AnimationDrawable.

¿Alguien sabe cómo extraer marcos de GIF animados y convertir cada uno de ellos en Drawable ?

Leonti
fuente
3
¿Te refieres a Android, o extraer marcos de un gif con una herramienta externa?
Osmund
definitivamente es un error, vea IssueTracker para más información.
fbtb
Solo para todos aquellos que vinieron aquí buscando una aplicación que pueda mostrar GIF animados: quickPic
rubo77
Use fresco para mostrar GIF github.com/facebook/fresco Creo que esta es una solución simple.
kaitian521

Respuestas:

191

Android en realidad puede decodificar y mostrar GIF animados, usando la clase android.graphics.Movie.

Esto no está demasiado documentado, pero está en SDK Reference . Además, se usa en Muestras en ApiDemos en el ejemplo BitmapDecode con alguna bandera animada.

Puntero nulo
fuente
9
¿Qué tan estable es esto? Lo he implementado en mi aplicación, en mi dispositivo Ice Cream Sandwich no funciona en absoluto, en un emulador 2.3 funciona, pero algunos de los marcos GIF tienen errores (colores incorrectos). En una computadora, por supuesto, funciona bien. ¿Lo que da?
Benoit Duffez
12
@Bicou En dispositivos posteriores a HC, debería hacerlo setLayerType(LAYER_TYPE_SOFTWARE)en su Vista. Pero todavía solo funciona para algunos gifs y para algunos dispositivos.
Michał K
9
@ MichałK ¡Gracias! Paint p = new Paint(); p.setAntiAlias(true); setLayerType(LAYER_TYPE_SOFTWARE, p);¡trabajó!
Chloe
1
@lubosz: LAYER_TYPE_SOFTWARE debería ser suficiente para configurar.
Puntero nulo el
2
La clase de película no está documentada a propósito, es débil y no es compatible. Si necesita animaciones Gif adecuadas, es mejor que lo implemente usted mismo. Lo hice para mi aplicación usando NDK.
Puntero nulo
60

ACTUALIZAR:

Usar deslizamiento:

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

uso:

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

ver documentos

itzhar
fuente
1
Ahora me parece bien, obviamente la respuesta no puede incluir toda la biblioteca, por lo que el ejemplo de llamada parece suficiente.
gaborous
@gaborous Obviamente, el código no estaba incluido en el momento del marcado.
Jan
1
No recomiendo usar esta biblioteca si ya está usando el NDK. Después de agregar esta lib a gradle, un módulo de Unity dejó de funcionar.
RominaV
Esta es la mejor biblioteca que he encontrado. Una cosa en la que estoy atrapado es implementar pellizcar para hacer zoom en la imagen gif. ¿Alguien sabe?
víbora
28

también poner (main / assets / htmls / name.gif) [con este html ajustar al tamaño]

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

declare en su Xml, por ejemplo, así (main / res / layout / name.xml): [usted define el tamaño, por ejemplo]

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

en su Actividad ponga el siguiente código dentro de onCreate

web = (WebView) findViewById(R.id.webView); 
web.setBackgroundColor(Color.TRANSPARENT); //for gif without background
web.loadUrl("file:///android_asset/htmls/name.html");

si desea cargar dinámicamente, debe cargar la vista web con datos:

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

sugerencia: es mejor cargar gif con imágenes estáticas para obtener más información, consulte https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

Eso es todo, espero que ayudes.

Alex Zaraos
fuente
2
Si quiero cargar GIF desde la tarjeta sd?
Jaydev
si desea cargar desde la tarjeta sd: reemplace "file: ///android_asset/htmls/name.html" por el uri de su imagen
Alex Zaraos
Con este método, ¿cómo puedo cambiar el nombre del archivo gif dinámicamente? No quiero hacer un archivo html para cada GIF que necesito mostrar en mi aplicación
scrayne
Webview para un GIF?!? ¿Pensaste en el rendimiento, el consumo de memoria y la batería?
Duna
@Duna que fue hace 5 años, actualmente podemos usar deslizamiento, por ejemplo
Alex Zaraos el
22

Resolví el problema dividiendo las animaciones gif en marcos antes de guardarlo en el teléfono, para no tener que lidiar con eso en Android.

Luego descargo cada fotograma en el teléfono, creo Drawable a partir de él y luego creo AnimationDrawable , muy similar al ejemplo de mi pregunta

Leonti
fuente
2
Cuál es la forma documentada de manejar animaciones.
RichieHH
16

Encontré una manera muy fácil, con un ejemplo de trabajo agradable y simple aquí

mostrar widget animado

Antes de que funcione, hay algunos cambios que hacer en el código

EN EL SIGUIENTE

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

solo reemplace

setContentView(new MYGIFView());

en

setContentView(new MYGIFView(this));

Y EN

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

Proporcione su propio archivo de animación gif

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

REEMPLAZA LA PRIMERA LÍNEA EN

public MYGIFView(Context context) {

según el nombre de la clase ...

después de hacer estos pequeños cambios, debería funcionar para mí ...

espero que esto ayude

Apperside
fuente
2
¿En qué versión de Android intentaste esto? Intenté en la versión de Android 2.2 y 2.3 pero devuelve el objeto Movie nulo. ¿Alguna idea de lo que puede estar mal?
Ashwini Shahapurkar
16
Limpia esta respuesta, es así, al azar.
taxeeta
2
¿Cuál es el problema con la respuesta? Acabo de proporcionar un enlace y algunas soluciones necesarias para que funcione
Apperside
10

Formas de mostrar GIF animados en Android:

  • Clase de cine. Como se mencionó anteriormente, es bastante defectuoso.
  • WebView. Es muy simple de usar y generalmente funciona. Pero a veces comienza a comportarse mal, y siempre está en algunos dispositivos oscuros que no tiene. Además, no puede usar varias instancias en ningún tipo de vistas de lista, porque hace cosas en su memoria. Aún así, podría considerarlo como un enfoque primario.
  • Código personalizado para decodificar gifs en mapas de bits y mostrarlos como Drawable o ImageView. Mencionaré dos bibliotecas:

https://github.com/koral--/android-gif-drawable : el decodificador se implementa en C, por lo que es muy eficiente.

https://code.google.com/p/giffiledecoder : el decodificador se implementa en Java, por lo que es más fácil trabajar con él. Sigue siendo razonablemente eficiente, incluso con archivos grandes.

También encontrará muchas bibliotecas basadas en la clase GifDecoder. También es un decodificador basado en Java, pero funciona cargando todo el archivo en la memoria, por lo que solo es aplicable a archivos pequeños.

Nick Frolov
fuente
10

Me costó mucho tener gif animados trabajando en Android. Solo tenía dos siguientes trabajando:

  1. WebView
  2. Ion

WebView funciona bien y es muy fácil, pero el problema es que hace que la vista se cargue más lentamente y la aplicación no responda por un segundo más o menos. A mi no me gusto eso. Así que probé diferentes enfoques (NO FUNCIONÓ):

  1. ImageViewEx está en desuso!
  2. picasso no cargó gif animado
  3. android-gif-drawable se ve muy bien, pero causó algunos problemas de NDK con cable en mi proyecto. Causó que mi biblioteca local de NDK dejara de funcionar y no pude solucionarlo

Tuve un poco de ida y vuelta con Ion; Finalmente, lo tengo funcionando, y es realmente rápido :-)

Ion.with(imgView)
  .error(R.drawable.default_image)
  .animateGif(AnimateGifMode.ANIMATE)
  .load("file:///android_asset/animated.gif");
Roozbeh Zabihollahi
fuente
Tuve los mismos problemas relacionados con NDK con android-gif-drawable.
RominaV
Hola @RominaV, ¿Has utilizado la barra de progreso en Ion cuando cargas gif, porque necesito mostrar el progreso cuando cargo gif.
patel135
9

Glide 4.6

1. Para cargar gif

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

2. Para obtener el objeto de archivo

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);
                    }
                });
Gowsik KC
fuente
8

Glide

Image Loader Library para Android, recomendado por Google.

  • Glide es bastante similar a Picasso, pero esto es mucho más rápido que Picasso.
  • Glide consume menos memoria que Picasso.

Lo que ese Glide tiene pero Picasso no

La capacidad más interesante de Glide es la capacidad de cargar Animación GIF en un simple ImageView. Y sí, no puedes hacer eso con Picasso. Algunos enlaces importantesingrese la descripción de la imagen aquí

  1. https://github.com/bumptech/glide
  2. http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
Shoeb Siddique
fuente
¿Dónde recomienda Google Glid?
Derzu
1
Vea esto, donde el equipo desarrollador de Android usó Glide en su aplicación de muestra. developer.android.com/samples/XYZTouristAttraction/Application/…
Shoeb Siddique
1
'Glide es bastante similar a Picasso, pero esto es mucho más rápido que Picasso' y 'Glide consume menos memoria que Picasso'. Lo siento, no estoy contento con estas ideas, prefiera este enlace: medium.com/@multidots/glide-vs-picasso-930eed42b81d . Por cierto, no puedo probar Glide 4.0 ahora porque no puedo actualizar la compilación a 3.0.1 (conexión lenta a Internet); pero probé Glide 3.5.2 para mostrar gif, funciona pero no perfectamente como esperaba en img grande (parpadea), y este es un problema común también. Por favor, CMIW.
Nguyen Tan Dat
7

Use ImageViewEx , una biblioteca que hace que usar un gif sea tan fácil como usar un ImageView.

NightSkyCode
fuente
Esto ha quedado en desuso
Martin Marconcini
He revisado este código de bibliotecas, debería ser bueno durante 2 años más o menos.
NightSkyCode
1
Sí, creo que está relativamente bien, solo señalando que el autor ha decidido desaprobarlo. (y, por lo tanto, no mantenerlo), señalando que deberíamos usar algo como Picasso, lo cual es extraño, porque Picasso es un descargador de imágenes y no lo ayudará cuando se trata de mostrar un gif animado más que cualquiera de las muchas descargas / caché herramientas por ahí.
Martin Marconcini
6

Pruebe esto, debajo del archivo gif de visualización de código en la barra de progreso

loading_activity.xml (en la carpeta Diseño)

<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 (en carpeta dibujable)

aquí pongo black_gif.gif (en una carpeta dibujable), puedes poner tu propio gif aquí

<?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 (en la carpeta 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);

    }

}
nirav kalola
fuente
Te veo rotar el gif. ¿Por qué?
AlikElzin-kilaka
¿Cómo puedes poner gif en una carpeta dibujable?
Apurva
6

Nadie ha mencionado la biblioteca Ion o Glide . Funcionan muy bien.

Es más fácil de manejar en comparación con un WebView.

bapho
fuente
5

He tenido éxito con la solución propuesta en este artículo , una clase llamada GifMovieView, que representa una Viewque luego se puede mostrar o agregar a una específica ViewGroup. Consulte los otros métodos presentados en las partes 2 y 3 del artículo especificado.

El único inconveniente de este método es que el antialiasing en la película no es tan bueno (debe ser un efecto secundario del uso de la MovieClase Android "sombría" ). Entonces es mejor configurar el fondo a un color sólido dentro de su GIF animado.

Dr1Ku
fuente
4

Algunas reflexiones sobre el ejemplo de BitmapDecode ... Básicamente usa la clase de película antigua, pero sin características de android.graphics. En versiones recientes de API, debe desactivar la aceleración de hardware, como se describe aquí . Fue segfaulting para mí de lo contrario.

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

Aquí está el ejemplo de BitmapDecode acortado con solo la parte GIF. Tienes que hacer tu propio Widget (Ver) y dibujarlo tú mismo. No es tan poderoso como un 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();
            }
        }
    }
}

Se pueden encontrar otros 2 métodos, uno con ImageView y otro con WebView en este excelente tutorial . El método ImageView utiliza el Android-gifview con licencia de Apache de Google Code.

lubosz
fuente
1
@luboz, ¿puede decirme qué método es bueno para el rendimiento de Android? Quiero usar gif animado para la barra de carga de la pantalla de inicio. Entonces, ¿podría sugerir qué método es mejor? También quiero saber que al usar el método de vista de imagen, ¿es posible usar la propiedad de tipo de escala?
Swap-IOS-Android
4

@PointerNull dio una buena solución, pero no es perfecta. No funciona en algunos dispositivos con archivos grandes y muestra animaciones GIF con errores con marcos delta en la versión pre ICS. Encontré solución sin estos errores. Es una biblioteca con decodificación nativa para dibujable : koral's android-gif-drawable .

Sergei Vasilenko
fuente
2

Póngalo en un WebView, debe poder mostrarlo correctamente, ya que el navegador predeterminado admite archivos gif. (Froyo +, si no me equivoco)

keybee
fuente
Esto no es verdad. No todos los navegadores admiten GIF.
RichieHH
44
Esperemos que no necesitemos todos los navegadores ... Stock browser lo admite desde Android 2.2, así que no me denigren, por favor. ¡Un WebView definitivamente mostrará el GIF!
keybee
2

Hay dos opciones para cargar gifs animados en nuestras aplicaciones de Android

1) Usando Glide para cargar el gif en un 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) Usar un html para cargar el gif en un WebView

Cree el html con la dirección del archivo .gif:

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

almacene este archivo en el directorio de activos:

ingrese la descripción de la imagen aquí

Cargue este html en el WebView de su aplicación:

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

Heres es un ejemplo completo de estas dos opciones .

ingrese la descripción de la imagen aquí

Jorgesys
fuente
2

Solo para Android API (Android Pie) 28 y +

utilizar AnimatedImageDrawable como

// 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()

Código XML, agregue un 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 es hijo de Drawable y creado por ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawableque además requería la instancia de ImageDecoder.Sourcecreado por ImageDecoder.createSource.

ImageDecoder.createSourcesolo puede tomar la fuente como nombre, ByteBuffer, File, resourceId, URI, ContentResolver para crear el objeto fuente y lo usa para crear AnimatedImageDrawablecomo Drawable(llamada polimórfica)

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)

Nota: También puede crear Bitmapusando ImageDecoder # decodeBitmap .

Salida:

AnimatedDrawable también admite el cambio de tamaño, la manipulación de marcos y colores

Pavneet_Singh
fuente
1

Creo que la mejor biblioteca para manejar archivos gif es esta: por koral

Lo usé y tengo éxito y esta biblioteca está dedicada a GIF'S; pero donde como picasso y glide son marco de imagen de uso general ; así que creo que los desarrolladores de esta biblioteca se han concentrado completamente en archivos gif

DJphy
fuente
1

Solo quería agregar que la clase Movie ahora está en desuso.

Esta clase fue desaprobada en el nivel de API P.

Se recomienda usar esto

AnimatedImageDrawable

Dibujable para dibujar imágenes animadas (como GIF).

Sushobh Nadiger
fuente
1

Cree un paquete llamado "Utils" en la carpeta src y cree una clase llamada "GifImageView"

public class GifImageView extends View {
    private InputStream mInputStream;
    private Movie mMovie;
    private int mWidth, mHeight;
    private long mStart;
    private Context mContext;
    public GifImageView(Context context) {
        super(context);
        this.mContext = context;
    }
    public GifImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public GifImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        if (attrs.getAttributeName(1).equals("background")) {
            int id = Integer.parseInt(attrs.getAttributeValue(1).substring(1));
            setGifImageResource(id);
        }
    }
    private void init() {
        setFocusable(true);
        mMovie = Movie.decodeStream(mInputStream);
        mWidth = mMovie.width();
        mHeight = mMovie.height();
        requestLayout();
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(mWidth, mHeight);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        long now = SystemClock.uptimeMillis();
        if (mStart == 0) {
            mStart = now;
        }
        if (mMovie != null) {
            int duration = mMovie.duration();
            if (duration == 0) {
                duration = 1000;
            }
            int relTime = (int) ((now - mStart) % duration);
            mMovie.setTime(relTime);
            mMovie.draw(canvas, 0, 0);
            invalidate();
        }
    }
    public void setGifImageResource(int id) {
        mInputStream = mContext.getResources().openRawResource(id);
        init();
    }
    public void setGifImageUri(Uri uri) {
        try {
            mInputStream = mContext.getContentResolver().openInputStream(uri);
            init();
        } catch (FileNotFoundException e) {
            Log.e("GIfImageView", "File not found");
        }
    }
}

Ahora defina GifImageView en el archivo MainActivity: src / activity / MainActivity.class

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        GifImageView gifImageView = (GifImageView) findViewById(R.id.GifImageView);
        gifImageView.setGifImageResource(R.drawable.smartphone_drib);
    }
}

Ahora archivo de parte de la interfaz de usuario: res / layout / activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:gravity="center"
    android:background="#111E39"
    tools:context=".Activity.MainActivity">
    <com.android.animatedgif.Utils.GifImageView
        android:id="@+id/GifImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

Código Resourece: ejemplo de Android

Tienanhvn
fuente
cómo cambiar el tamaño de la imagen, por favor
The Dead Guy
0

En primer lugar, el navegador de Android debe admitir GIF animados. Si no es así, ¡es un error! Echa un vistazo a los rastreadores de problemas.

Si está mostrando estos GIF animados fuera de un navegador, podría ser una historia diferente. Hacer lo que está pidiendo requeriría una biblioteca externa que admita la decodificación de GIF animados.

El primer puerto de escala sería mirar la API Java2D o JAI (Java Advanced Imaging), aunque me sorprendería mucho si Android Dalvik admitiera esas bibliotecas en su aplicación.

Eurig Jones
fuente
algunos dispositivos no muestran gifs animados, incluso en un navegador web. Como ejemplo, sé que Galaxy Mini con Android 2.3.6 no los muestra.
desarrollador de Android
0

Similar a lo que dijo @Leonti, pero con un poco más de profundidad:

Lo que hice para resolver el mismo problema fue abrir GIMP, ocultar todas las capas excepto una, exportarla como su propia imagen, y luego ocultar esa capa y mostrar la siguiente, etc., hasta que tuviera archivos de recursos individuales para cada una. . Entonces podría usarlos como cuadros en el archivo XML AnimationDrawable.

Jon O
fuente
1
Podrías usar gifsicle para extraer los marcos si no tienes tanto tiempo. También python o bash son muy útiles al generar archivos xml.
lubosz
0

Resolví esto al dividir gif en marcos y usar animación estándar de Android

Raluca Lucaci
fuente
0

Algo que hice para mostrar gifs en aplicaciones. Extendí ImageView para que las personas puedan usar sus atributos libremente. Puede mostrar gifs desde url o desde el directorio de activos. La biblioteca también facilita la extensión de las clases para heredar de ella y la extiende para admitir diferentes métodos para inicializar el gif.

https://github.com/Gavras/GIFView

Hay una pequeña guía en la página de Github.

También se publicó en Android Arsenal:

https://android-arsenal.com/details/1/4947

Use ejemplo:

De XML:

<com.whygraphics.gifview.gif.GIFView xmlns:gif_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/main_activity_gif_vie"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:scaleType="center"
        gif_view:gif_src="url:http://pop.h-cdn.co/assets/16/33/480x264/gallery-1471381857-gif-season-2.gif" />

En la actividad:

    GIFView mGifView = (GIFView) findViewById(R.id.main_activity_gif_vie);

    mGifView.setOnSettingGifListener(new GIFView.OnSettingGifListener() {
                @Override
                public void onSuccess(GIFView view, Exception e) {
                    Toast.makeText(MainActivity.this, "onSuccess()", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailure(GIFView view, Exception e) {

        }
});

Configurar el gif mediante programación:

mGifView.setGifResource("asset:gif1");
Tzlil Gavra
fuente
0

La forma más fácil: se puede considerar el siguiente código

Podemos aprovechar Imageview setImageResource, consulte el siguiente código para el mismo.

El siguiente código se puede usar para mostrar la imagen como gif en caso de que tenga la imagen dividida múltiple de gif. Simplemente divida el gif en png individual desde una herramienta en línea y coloque la imagen en el dibujo como en el siguiente orden

image_1.png, image_2.png, etc.

Tener el controlador para cambiar la imagen dinámicamente.

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);
// 
                    }
                });
              }
Lakshmanan
fuente
0

La manera fácil de mostrar GIF animados directamente desde la URL al diseño de su aplicación es usar la clase WebView.

Paso 1: en su diseño XML

<WebView
android:id="@+id/webView"
android:layout_width="50dp"
android:layout_height="50dp"
/>

Paso 2: en tu actividad

WebView wb;
wb = (WebView) findViewById(R.id.webView);
wb.loadUrl("https://.......);

Paso 3: En su Manifiesto.XML, haga permiso en Internet

<uses-permission android:name="android.permission.INTERNET" />

Paso 4: en caso de que desee que su fondo GIF sea transparente y que el GIF se ajuste a su diseño

wb.setBackgroundColor(Color.TRANSPARENT);
wb.getSettings().setLoadWithOverviewMode(true);
wb.getSettings().setUseWideViewPort(true);

Ovais Chaudhry
fuente
Gracias por la solución, pero una considerable desarrollador podría no querer tener no nativo render por algunas implicaciones como un efecto de memoria, uso de CPU y la batería vida
Rux
-8
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());

      }
    }
  }
}
Ashok Domadiya
fuente