Animiertes GIF anzeigen


261

Ich möchte animierte GIF-Bilder in meiner Anwendung anzeigen. Wie ich auf die harte Tour herausgefunden habe, unterstützt Android animiertes GIF nicht nativ.

Allerdings kann es Animationen mit Anzeige AnimationDrawable :

Entwickeln> Anleitungen> Bilder und Grafiken> Drawables - Übersicht

Das Beispiel verwendet Animationen, die als Frames in Anwendungsressourcen gespeichert sind. Ich muss jedoch animiertes GIF direkt anzeigen.

Mein Plan ist es, animiertes GIF in Frames zu unterteilen und jedes Frame als zeichnbar zu AnimationDrawable hinzuzufügen.

Weiß jemand, wie man Frames aus animiertem GIF extrahiert und in Drawable konvertiert ?


3
Meinen Sie innerhalb von Android oder das Extrahieren von Frames aus einem GIF mit einem externen Tool?
Osmund

Es ist definitiv ein Fehler. Weitere Informationen finden Sie unter IssueTracker .
fbtb

Nur für alle, die hierher gekommen sind, indem sie nach einer App gesucht haben, die animierte GIFs anzeigen kann: quickPic
rubo77


Verwenden Sie Fresko, um GIF anzuzeigen. Github.com/facebook/fresco Ich denke, dies ist eine einfache Lösung.
Kaitian521

Antworten:


191

Android kann mithilfe der android.graphics.Movie-Klasse animierte GIFs dekodieren und anzeigen.

Dies ist nicht zu stark dokumentiert, befindet sich jedoch in der SDK-Referenz . Darüber hinaus wird es in Beispielen in ApiDemos im BitmapDecode- Beispiel mit einem animierten Flag verwendet.


9
Wie stabil ist das? Ich habe es in meiner App implementiert, auf meinem Ice Cream Sandwich-Gerät funktioniert es überhaupt nicht, auf einem 2.3-Emulator funktioniert es, aber einige der GIF-Frames sind fehlerhaft (falsche Farben). Auf einem Computer funktioniert es natürlich gut. Was gibt?
Benoit Duffez

12
@Bicou Auf Post-HC-Geräten sollten Sie setLayerType(LAYER_TYPE_SOFTWARE)in Ihrer Ansicht. Aber es funktioniert immer noch nur für einige Gifs und für einige Geräte.
Michał K

9
@ MichałK Danke! Paint p = new Paint(); p.setAntiAlias(true); setLayerType(LAYER_TYPE_SOFTWARE, p);hat funktioniert!
Chloe

1
@lubosz: LAYER_TYPE_SOFTWARE sollte zum Einstellen ausreichen.
Zeiger Null

2
Der Filmunterricht ist absichtlich nicht dokumentiert - er ist schwach und wird nicht unterstützt. Wenn Sie geeignete Gif-Animationen benötigen, implementieren Sie diese besser selbst. Ich habe es für meine App mit NDK gemacht.
Zeiger Null

60

AKTUALISIEREN:

Gleiten verwenden:

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

Verwendung:

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

siehe docs


1
Sieht für mich jetzt in Ordnung aus, offensichtlich kann die Antwort nicht die gesamte Bibliothek enthalten, daher scheint das Anrufbeispiel ausreichend zu sein.
gaborous

@gaborous Offensichtlich war der Code zum Zeitpunkt des Markierens nicht enthalten.
Januar

1
Ich empfehle die Verwendung dieser Bibliothek nicht, wenn Sie das NDK bereits verwenden. Nach dem Hinzufügen dieser Bibliothek zu gradle funktionierte ein Unity-Modul nicht mehr.
RominaV

Dies ist die beste Bibliothek, die ich gefunden habe. Eine Sache, in der ich stecke, ist die Implementierung einer Prise, um das GIF-Bild zu zoomen. Weiss es jemand?
Viper

28

auch put (main / assets / htmls / name.gif) [mit diesem HTML an die Größe anpassen]

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

Deklarieren Sie in Ihrer XML beispielsweise Folgendes (main / res / layout / name.xml): [Sie definieren beispielsweise die Größe]

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

Fügen Sie in Ihrer Aktivität den nächsten Code in onCreate ein

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

Wenn Sie dynamisch laden möchten, müssen Sie die Webansicht mit Daten laden:

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

Vorschlag: Laden Sie GIF besser mit statischen Bildern. Weitere Informationen finden Sie unter https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

Das war's, ich hoffe du hilfst.


2
Wenn ich GIF von SD-Karte laden möchte?
Jaydev

Wenn Sie von SD-Karte laden möchten: Ersetzen Sie "Datei: ///android_asset/htmls/name.html" für die URL Ihres Bildes
Alex Zaraos

Wie kann ich mit dieser Methode den Namen der GIF-Datei dynamisch ändern? Ich möchte nicht eine HTML-Datei erstellen, die zu jedem
GIF passt, das

Webview für ein GIF?!? Haben Sie über Leistung, Speicherverbrauch und Akku nachgedacht?
Duna

@ Duna, die vor 5 Jahren war, derzeit können wir zum Beispiel Gleiten verwenden
Alex Zaraos

22

Ich habe das Problem gelöst, indem ich GIF- Animationen in Frames aufgeteilt habe, bevor ich sie auf dem Telefon gespeichert habe, damit ich mich in Android nicht darum kümmern muss.

Dann lade ich jeden Frame auf das Telefon herunter, erstelle daraus Drawable und erstelle dann AnimationDrawable - sehr ähnlich dem Beispiel aus meiner Frage


2
Welches ist die dokumentierte Art des Umgangs mit Animationen.
RichieHH

16

Ich habe einen sehr einfachen Weg gefunden, mit einem schönen und einfachen Arbeitsbeispiel hier

animiertes Widget anzeigen

Bevor es funktioniert, müssen im Code einige Änderungen vorgenommen werden

IM FOLGENDEN

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

einfach ersetzen

setContentView(new MYGIFView());

im

setContentView(new MYGIFView(this));

UND IN

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

Stellen Sie Ihre eigene GIF-Animationsdatei bereit

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

ERSETZEN SIE DIE ERSTE LINIE IN

public MYGIFView(Context context) {

nach dem Namen der Klasse ...

Nach diesen kleinen Änderungen sollte es wie bei mir funktionieren ...

Ich hoffe das hilft


2
Auf welcher Android-Version hast du das versucht? Ich habe Android Version 2.2 und 2.3 ausprobiert, aber es gibt das Movie-Objekt null zurück. Irgendeine Idee, was falsch sein kann?
Ashwini Shahapurkar

16
Bitte bereinigen Sie diese Antwort, es ist so, zufällig.
Taxeeta

2
Was ist das Problem mit der Antwort? Ich habe gerade einen Link und einige notwendige Korrekturen bereitgestellt, damit es funktioniert
Apperside

10

Möglichkeiten, animiertes GIF auf Android anzuzeigen:

  • Filmklasse. Wie oben erwähnt, ist es ziemlich fehlerhaft.
  • WebView. Es ist sehr einfach zu bedienen und funktioniert normalerweise . Aber manchmal fängt es an, sich schlecht zu benehmen, und es ist immer auf einigen obskuren Geräten, die Sie nicht haben. Außerdem können Sie nicht mehrere Instanzen in Listenansichten verwenden, da dies zu Problemen mit Ihrem Speicher führt. Dennoch könnten Sie es als primären Ansatz betrachten.
  • Benutzerdefinierter Code zum Dekodieren von Gifs in Bitmaps und Anzeigen als Drawable oder ImageView. Ich werde zwei Bibliotheken erwähnen:

https://github.com/koral--/android-gif-drawable - Der Decoder ist in C implementiert und daher sehr effizient.

https://code.google.com/p/giffiledecoder - Der Decoder ist in Java implementiert, sodass die Arbeit einfacher ist. Selbst bei großen Dateien immer noch einigermaßen effizient.

Sie finden auch viele Bibliotheken, die auf der GifDecoder-Klasse basieren. Das ist auch ein Java-basierter Decoder, aber er lädt die gesamte Datei in den Speicher, sodass er nur für kleine Dateien gilt.


10

Es fiel mir wirklich schwer, animiertes GIF in Android zu haben. Ich hatte nur zwei Arbeiten:

  1. WebView
  2. Ion

WebView funktioniert einwandfrei und ist sehr einfach. Das Problem ist jedoch, dass die Ansicht langsamer geladen wird und die App etwa eine Sekunde lang nicht reagiert. Ich mochte das nicht. Also habe ich verschiedene Ansätze ausprobiert (NICHT ARBEITEN):

  1. ImageViewEx ist veraltet!
  2. Picasso hat kein animiertes gif geladen
  3. android-gif-drawable sieht aus, hat aber in meinem Projekt einige Probleme mit kabelgebundenen NDK verursacht. Dadurch funktionierte meine lokale NDK-Bibliothek nicht mehr und ich konnte das Problem nicht beheben

Ich hatte einige hin und her mit Ion; Endlich habe ich es geschafft und es ist wirklich schnell :-)

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

Ich hatte die gleichen NDK-bezogenen Probleme mit Android-GIF-Drawable.
RominaV

Hallo @RominaV, Haben Sie beim Laden von GIF den Fortschrittsbalken in Ion verwendet, da ich beim Laden von GIF den Fortschritt anzeigen muss?
Patel135

9

Gleiten 4.6

1. Gif laden

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

2. Um das Dateiobjekt abzurufen

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

8

Glide

Image Loader Library für Android, empfohlen von Google.

  • Glide ist Picasso ziemlich ähnlich, aber dies ist viel schneller als Picasso.
  • Glide verbraucht weniger Speicher als Picasso.

Was dieser Glide hat, aber Picasso nicht

Die Möglichkeit, GIF-Animationen in eine einfache ImageView zu laden, ist möglicherweise die interessanteste Funktion von Glide. Und ja, das geht mit Picasso nicht. Einige wichtige Links-Geben Sie hier die Bildbeschreibung ein

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

Wo empfiehlt Google Glid?
Derzu

1
Sehen Sie hier, wo das Entwickler-Android-Team den Glide in seiner Beispiel-App verwendet hat. developer.android.com/samples/XYZTouristAttractions/Application/…
Shoeb Siddique

1
"Glide ist Picasso ziemlich ähnlich, aber dies ist viel schneller als Picasso" und "Glide verbraucht weniger Speicher als Picasso." Entschuldigung, ich bin mit diesen Ideen nicht zufrieden. Bitte bevorzugen Sie diesen Link: medium.com/@multidots/glide-vs-picasso-930eed42b81d . Übrigens kann ich Glide 4.0 jetzt nicht testen, da ich Build nicht auf 3.0.1 aktualisieren kann (langsame Internetverbindung). Aber ich habe Glide 3.5.2 getestet, um GIF zu zeigen. Es funktioniert aber nicht perfekt, wie ich es bei großen IMGs erwartet hatte (es flackert), und dies ist auch ein häufiges Problem. Bitte CMIW.
Nguyen Tan Dat

7

Verwenden Sie ImageViewEx , eine Bibliothek, die die Verwendung eines Gifs so einfach macht wie die Verwendung eines ImageView.


Dies ist veraltet
Martin Marconcini

Ich habe diesen Bibliothekscode durchgesehen, er sollte noch ungefähr zwei Jahre gültig sein.
NightSkyCode

1
Ja, ich denke, es ist relativ gut, nur darauf hinzuweisen, dass der Autor beschlossen hat, es abzulehnen. (und daher nicht beibehalten) und darauf hinweisen, dass wir so etwas wie Picasso verwenden sollten, was seltsam ist, da Picasso ein Bild-Downloader ist und Ihnen beim Anzeigen eines animierten Gifs nicht mehr hilft als jeder der vielen Downloads / Caches Werkzeuge da draußen.
Martin Marconcini

6

Versuchen Sie dies, GIF-Datei mit der folgenden Code-Anzeige in der Fortschrittsleiste

load_activity.xml (im Ordner 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 (im zeichnbaren Ordner)

hier lege ich black_gif.gif (in zeichnbaren Ordner), hier kannst du dein eigenes gif einfügen

<?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 (im res-Ordner)

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

    }

}

Ich sehe, du drehst das GIF. Warum?
AlikElzin-Kilaka

Wie können Sie GIF in einen Zeichenordner legen?
Apurva

6

Niemand hat die Ion- oder Glide- Bibliothek erwähnt. Sie arbeiten sehr gut.

Es ist einfacher zu handhaben als ein WebView.


5

Ich hatte Erfolg mit der in diesem Artikel vorgeschlagenen Lösung , einer Klasse namens GifMovieView, die eine rendert, Viewdie dann angezeigt oder einer bestimmten hinzugefügt werden kannViewGroup . Schauen Sie sich die anderen Methoden an, die in Teil 2 und 3 des angegebenen Artikels vorgestellt werden.

Der einzige Nachteil dieser Methode ist, dass das Antialiasing des Films nicht so gut ist (muss ein Nebeneffekt bei der Verwendung der "zwielichtigen" Android- MovieKlasse sein). Sie sollten den Hintergrund in Ihrem animierten GIF besser auf eine Volltonfarbe einstellen.


4

Einige Gedanken über das BitmapDecode Beispiel ... Im Grunde verwendet es die alten, sondern eher gesichtsFilmKlasse von android.graphics. In neueren API-Versionen müssen Sie die Hardwarebeschleunigung wie hier beschrieben deaktivieren . Ansonsten war es für mich ein Segfault.

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

Hier ist das BitmapDecode-Beispiel, das nur mit dem GIF-Teil gekürzt wurde. Sie müssen Ihr eigenes Widget (Ansicht) erstellen und es selbst zeichnen. Nicht ganz so leistungsfähig wie ein 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();
            }
        }
    }
}

In diesem schönen Tutorial finden Sie zwei weitere Methoden, eine mit ImageView und eine andere mit WebView . Die ImageView-Methode verwendet die Apache-lizenzierte Android-Gifview von Google Code.


1
@luboz kannst du mir bitte sagen, welche Methode für die Android-Leistung gut ist ... Ich möchte animiertes GIF für die Ladeleiste des Begrüßungsbildschirms verwenden. Können Sie uns bitte vorschlagen, welche Methode besser ist? Ich möchte auch wissen, dass es mit der Bildansichtsmethode möglich ist, die Skalentyp-Eigenschaft zu verwenden.
Swap-IOS-Android

4

@PointerNull gab eine gute Lösung, aber es ist nicht perfekt. Es funktioniert nicht auf einigen Geräten mit großen Dateien und zeigt fehlerhafte Gif-Animationen mit Delta-Frames in der Vor-ICS-Version. Ich habe eine Lösung ohne diese Fehler gefunden. Es ist eine Bibliothek mit nativer Dekodierung zum Zeichnen: Korals Android-GIF-Zeichnen .


2

Wenn Sie es in eine WebView einfügen, muss es korrekt angezeigt werden können, da der Standardbrowser GIF-Dateien unterstützt. (Froyo +, wenn ich mich nicht irre)


Das ist nicht wahr. Nicht alle Browser unterstützen GIF.
RichieHH

4
Hoffentlich brauchen wir nicht alle Browser ... Der Aktienbrowser unterstützt es seit Android 2.2, also stimmen Sie mich bitte nicht ab. Ein WebView zeigt definitiv das GIF an!
Keybee

2

Es gibt zwei Möglichkeiten, animierte Gifs in unsere Android-Apps zu laden

1) Verwenden Sie Glide , um das GIF in ein zu laden 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) Verwenden Sie ein HTML, um das GIF in ein zu laden WebView

Erstellen Sie den HTML-Code mit der Adresse der GIF-Datei:

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

Speichern Sie diese Datei im Assets-Verzeichnis:

Geben Sie hier die Bildbeschreibung ein

Das Laden dieses HTML in die WebView Ihrer Anwendung:

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

Hier ist ein vollständiges Beispiel für diese beiden Optionen .

Geben Sie hier die Bildbeschreibung ein


2

Nur für Android API (Android Pie) 28 und +

Verwenden Sie AnimatedImageDrawable als

// 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, fügen Sie eine ImageView hinzu

<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 ist ein Kind von Drawable und erstellt von ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawablewas weiter die Instanz von ImageDecoder.Sourceerstellt von erforderlich ImageDecoder.createSource.

ImageDecoder.createSourceQuelle kann nur als Name, ByteBuffer, Datei, Ressourcen-ID, URI, ContentResolver zum Erstellen des Quellobjekts verwendet werden und zum Erstellen AnimatedImageDrawableals Drawable(polymorpher Aufruf) verwendet werden.

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)

Hinweis: Sie können auch Bitmapmit ImageDecoder # decodeBitmap erstellen .

Ausgabe:

AnimatedDrawable unterstützt auch die Größenänderung, Rahmen- und Farbmanipulation


1

Ich denke, die bessere Bibliothek für den Umgang mit GIF- Dateien ist diese: von Koral

Ich habe es benutzt und bin erfolgreich und diese Bibliothek ist GIF'S gewidmet. aber wo als Picasso und Gleiten Allzweck- Bildrahmen sind ; Ich denke, die Entwickler dieser Bibliothek haben sich ganz auf GIF-Dateien konzentriert



1

Ich wollte nur hinzufügen, dass die Movie- Klasse jetzt veraltet ist.

Diese Klasse wurde in API-Level P veraltet.

Es wird empfohlen, dies zu verwenden

AnimatedImageDrawable

Zeichnbar zum Zeichnen animierter Bilder (wie GIF).


1

Erstellen Sie ein Paket mit dem Namen "Utils" im Ordner "src" und erstellen Sie eine Klasse mit dem Namen "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");
        }
    }
}

Definieren Sie nun GifImageView in der MainActivity-Datei: 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);
    }
}

Jetzt UI-Teiledatei: 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>

Ressourcencode: Android-Beispiel


wie man die Größe des Bildes ändert, pls
The Dead Guy

0

Zunächst sollte der Android-Browser animierte GIFs unterstützen. Wenn nicht, dann ist es ein Fehler! Schauen Sie sich die Issue-Tracker an.

Wenn Sie diese animierten GIFs außerhalb eines Browsers anzeigen, ist dies möglicherweise eine andere Geschichte. Um das zu tun, was Sie verlangen, benötigen Sie eine externe Bibliothek, die die Dekodierung von animierten GIFs unterstützt.

Die erste Anlaufstelle wäre ein Blick auf die Java2D- oder JAI-API (Java Advanced Imaging), obwohl ich sehr überrascht wäre, wenn Android Dalvik diese Bibliotheken in Ihrer App unterstützen würde.


Einige Geräte zeigen keine animierten Gifs an, selbst in einem Webbrowser. Als Beispiel weiß ich, dass Galaxy Mini mit Android 2.3.6 sie nicht zeigt.
Android-Entwickler

0

Ähnlich wie @Leonti, aber mit etwas mehr Tiefe:

Um dasselbe Problem zu lösen, habe ich GIMP geöffnet, alle Ebenen bis auf eine ausgeblendet, als eigenes Bild exportiert und dann diese Ebene ausgeblendet und die nächste usw. ausgeblendet, bis ich für jede einzelne Ressourcendatei hatte . Dann könnte ich sie als Frames in der XML-Datei AnimationDrawable verwenden.


1
Sie können Gifsicle verwenden , um die Frames zu extrahieren, wenn Sie nicht so viel Zeit haben. Auch Python oder Bash sind sehr praktisch beim Generieren von XML-Dateien.
Lubosz

0

Ich habe dies gelöst, indem ich GIF in Frames aufgeteilt und Standard-Android-Animationen verwendet habe


0

Etwas, das ich getan habe, um Gifs in Apps anzuzeigen. Ich habe ImageView erweitert, damit Benutzer die Attribute frei verwenden können. Es kann Gifs von der URL oder aus dem Assets-Verzeichnis anzeigen. Die Bibliothek erleichtert auch das Erweitern von Klassen, um von ihr zu erben, und das Erweitern, um verschiedene Methoden zum Initialisieren des GIF zu unterstützen.

https://github.com/Gavras/GIFView

Es gibt eine kleine Anleitung auf der Github-Seite.

Es wurde auch auf Android Arsenal veröffentlicht:

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

Anwendungsbeispiel:

Aus 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" />

In der Aktivität:

    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) {

        }
});

Programmgesteuertes Einstellen des GIF:

mGifView.setGifResource("asset:gif1");

0

Einfachster Weg - Kann den folgenden Code berücksichtigen

Wir können Imageview setImageResource nutzen, siehe unten Code für das gleiche.

Der folgende Code kann verwendet werden, um das Bild wie GIF-Incase anzuzeigen, wenn Sie das mehrfach geteilte Bild von GIF haben. Teilen Sie das GIF einfach über ein Online-Tool in ein einzelnes PNG auf und fügen Sie das Bild wie in der folgenden Reihenfolge in das Zeichenelement ein

image_1.png, image_2.png usw.

Lassen Sie den Handler das Bild dynamisch ändern.

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

0

Die einfache Möglichkeit, animiertes GIF direkt von der URL in Ihr App-Layout anzuzeigen, ist die Verwendung der WebView-Klasse.

Schritt 1: In Ihrem Layout XML

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

Schritt 2: In Ihrer Aktivität

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

Schritt 3: Machen Sie in Ihrer Manifest.XML die Internetberechtigung

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

Schritt 4: Falls Sie Ihren GIF-Hintergrund transparent machen und GIF an Ihr Layout anpassen möchten

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


Vielen Dank für die Problemumgehung, aber ein beträchtlicher Entwickler möchte möglicherweise kein nicht natives Rendering haben, da dies Auswirkungen auf den Speicher, die CPU-Auslastung und die Akkulaufzeit hat
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());

      }
    }
  }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.