Wyświetl animowany GIF

261

Chcę wyświetlać animowane obrazy GIF w mojej aplikacji. Jak się przekonałem, Android nie obsługuje natywnie animowanego GIF-a.

Może jednak wyświetlać animacje za pomocą AnimationDrawable :

Rozwijaj> Przewodniki> Obrazy i grafika> Przegląd Drawables

W przykładzie użyto animacji zapisanej jako ramki w zasobach aplikacji, ale potrzebuję bezpośrednio wyświetlić animowany gif.

Mój plan polega na rozbiciu animowanego GIF-a na ramki i dodawaniu każdej ramki jako animowalnej do AnimationDrawable.

Czy ktoś wie, jak wyodrębnić ramki z animowanego GIF-a i przekonwertować każdą z nich na Drawable ?

Leonti
źródło
2
Masz na myśli Androida, czy wyodrębnianie ramek z gif za pomocą zewnętrznego narzędzia?
Osmund
zdecydowanie jest to błąd, zobacz IssueTracker, aby uzyskać więcej informacji.
fbtb
Tylko dla wszystkich, którzy tu przybyli, szukając aplikacji, która może wyświetlać animowane pliki GIF: quickPic
rubo77
Użyj fresku, aby wyświetlić GIF github.com/facebook/fresco Myślę, że to proste rozwiązanie.
kaitian521

Odpowiedzi:

191

Android może dekodować i wyświetlać animowane pliki GIF, korzystając z klasy android.graphics.Movie.

Nie jest to zbytnio udokumentowane, ale znajduje się w Odniesieniu do SDK . Ponadto jest on używany w przykładach w ApiDemos w przykładzie BitmapDecode z pewną animowaną flagą.

Wskaźnik Null
źródło
9
Jak stabilna to jest? Zaimplementowałem to w mojej aplikacji, na moim urządzeniu Ice Cream Sandwich w ogóle nie działa, na emulatorze 2.3 działa, ale niektóre ramki GIF są wadliwe (niewłaściwe kolory). Na komputerze oczywiście działa dobrze. Co daje?
Benoit Duffez
12
@Bicou Na urządzeniach post-HC powinieneś setLayerType(LAYER_TYPE_SOFTWARE)na swoim View. Ale nadal działa tylko w przypadku niektórych gifów i niektórych urządzeń.
Michał K
9
@ MichałK Dziękujemy! Paint p = new Paint(); p.setAntiAlias(true); setLayerType(LAYER_TYPE_SOFTWARE, p);pracował!
Chloe
1
@lubosz: LAYER_TYPE_SOFTWARE powinno wystarczyć do ustawienia.
Wskaźnik Null
2
Klasa filmu jest celowo nieudokumentowana - jest słaba i nie jest obsługiwana. Jeśli potrzebujesz odpowiednich animacji Gif, lepiej zaimplementuj je sam. Zrobiłem to dla mojej aplikacji za pomocą NDK.
Pointer Null
60

AKTUALIZACJA:

Użyj poślizgu:

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

stosowanie:

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

zobacz dokumenty

itzhar
źródło
1
Teraz wydaje mi się OK, oczywiście odpowiedź nie może obejmować całej biblioteki, więc przykład wywołania wydaje się wystarczający.
ponury
@ gaborous Oczywiście kod nie został uwzględniony w momencie oflagowania.
Jan
1
Nie polecam korzystania z tej biblioteki, jeśli już korzystasz z NDK. Po dodaniu tej biblioteki do gradacji moduł Unity przestał działać.
RominaV
To najlepsza biblioteka, jaką znalazłem. Jedną z rzeczy, w których utknąłem, jest uszczypnięcie, aby powiększyć obraz gif. Czy ktoś wie?
viper
28

umieść także (main / asset / htmls / name.gif) [z tym HTML dostosuj do rozmiaru]

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

zadeklaruj w swoim Xml na przykład w ten sposób (main / res / layout / name.xml): [na przykład określasz rozmiar]

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

w swoim działaniu umieść następny kod wewnątrz onCreate

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

jeśli chcesz ładować dynamicznie, musisz załadować widok z danymi:

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

sugestia: lepiej załadować gif ze statycznymi obrazami, aby uzyskać więcej informacji, sprawdź https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

To wszystko, mam nadzieję, że pomożesz.

Alex Zaraos
źródło
2
Jeśli chcę załadować GIF z sdcard?
Jaydev
jeśli chcesz załadować z sdcard: zamień „file: ///android_asset/htmls/name.html” na uri swojego obrazu
Alex Zaraos
Za pomocą tej metody, jak mogę dynamicznie zmieniać nazwę pliku gif? Nie chcę tworzyć pliku HTML, który będzie
pasował do każdego gifa,
Webview dla GIF?!? Czy myślałeś o wydajności, zużyciu pamięci i baterii?
Duna,
@Duna, która była 5 lat temu, obecnie możemy na przykład użyć szybowania
Alex Zaraos,
22

Rozwiązałem problem, dzieląc animacje gif na ramki przed zapisaniem ich na telefonie, więc nie musiałbym sobie z tym poradzić w Androidzie.

Następnie pobieram każdą ramkę na telefon, tworzę z niej Drawable, a następnie tworzę AnimationDrawable - bardzo podobny do przykładu z mojego pytania

Leonti
źródło
2
Który jest udokumentowanym sposobem obsługi animacji.
RichieHH,
16

znalazłem bardzo łatwy sposób, z ładnym i prostym przykładem działania tutaj

wyświetlać animowany widżet

Zanim zacznie działać, należy wykonać kilka czynności w kodzie

W NASTĘPUJĄCYM

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

po prostu wymień

setContentView(new MYGIFView());

w

setContentView(new MYGIFView(this));

I W

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

Podaj własny plik animacji gif

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

WYMIENIĆ PIERWSZĄ LINIĘ W

public MYGIFView(Context context) {

zgodnie z nazwą klasy ...

po tych drobnych zmianach powinno działać jak dla mnie ...

Mam nadzieję, że to pomoże

Apperside
źródło
2
Na jakiej wersji Androida wypróbowałeś to? Próbowałem na Androidzie w wersji 2.2 i 2.3, ale zwraca obiekt filmowy null. Masz pojęcie, co może być nie tak?
Ashwini Shahapurkar
16
Wyczyść tę odpowiedź, więc jest losowa.
taxeeta
2
jaki jest problem z odpowiedzią? Właśnie
podałem
10

Sposoby wyświetlania animowanego GIF-a na Androidzie:

  • Klasa filmowa. Jak wspomniano powyżej, jest dość wadliwy.
  • WebView. Jest bardzo prosty w użyciu i zwykle działa. Ale czasem zaczyna się źle zachowywać i zawsze działa na niejasnych urządzeniach, których nie masz. Ponadto nie można używać wielu instancji w żadnym widoku listy, ponieważ ma to wpływ na pamięć. Mimo to możesz uznać to za podstawowe podejście.
  • Niestandardowy kod do dekodowania gifów do map bitowych i wyświetlania ich jako Drawable lub ImageView. Wspomnę o dwóch bibliotekach:

https://github.com/koral--/android-gif-drawable - dekoder jest zaimplementowany w C, więc jest bardzo wydajny.

https://code.google.com/p/giffiledecoder - dekoder jest zaimplementowany w Javie, więc łatwiej jest z nim pracować. Nadal dość wydajny, nawet przy dużych plikach.

Znajdziesz również wiele bibliotek opartych na klasie GifDecoder. Jest to również dekoder oparty na Javie, ale działa poprzez ładowanie całego pliku do pamięci, więc ma zastosowanie tylko do małych plików.

Nick Frolov
źródło
10

Bardzo ciężko mi było mieć animowany gif działający w systemie Android. Miałem tylko dwa następujące działania:

  1. WebView
  2. Jon

WebView działa OK i jest naprawdę łatwy, ale problem polega na tym, że widok ładuje się wolniej, a aplikacja nie reaguje przez sekundę. Nie podobało mi się to. Więc wypróbowałem różne podejścia (NIE DZIAŁAŁO):

  1. ImageViewEx jest przestarzały!
  2. Picasso nie załadował animowanego gif
  3. Android-gif-drawable wygląda świetnie, ale spowodował pewne problemy z przewodowym NDK w moim projekcie. Spowodowało to, że moja lokalna biblioteka NDK przestała działać i nie byłem w stanie tego naprawić

Miałem trochę tam iz powrotem Ion; Wreszcie mam działającą i jest naprawdę szybka :-)

Ion.with(imgView)
  .error(R.drawable.default_image)
  .animateGif(AnimateGifMode.ANIMATE)
  .load("file:///android_asset/animated.gif");
Roozbeh Zabihollahi
źródło
Miałem te same problemy związane z NDK z systemem Android-gif-drawable.
RominaV
Witaj @ RominaV, Czy używałeś paska postępu w Ion podczas ładowania gif, ponieważ muszę pokazać postęp podczas ładowania gif.
patel135
9

Szybkość 4.6

1. Aby załadować gif

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

2. Aby uzyskać obiekt pliku

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
źródło
8

Glide

Biblioteka Image Loader dla Androida, zalecana przez Google.

  • Szybownictwo jest dość podobne do Picassa, ale jest znacznie szybsze niż Picasso.
  • Szybownictwo zużywa mniej pamięci niż Picasso.

To, co ma Glide, ale nie Picasso

Możliwość załadowania animacji GIF do prostego ImageView może być najciekawszą funkcją Glide. I tak, nie możesz tego zrobić za pomocą Picassa. Kilka ważnych linkówwprowadź opis zdjęcia tutaj

  1. https://github.com/bumptech/glide
  2. http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
Shoeb Siddique
źródło
Gdzie Google poleca Glid?
Derzu
1
Zobacz, gdzie zespół programistów Androida wykorzystał Glide w swojej przykładowej aplikacji. developer.android.com/samples/XYZTouristAttractions/Application/…
Shoeb Siddique
1
„Szybownictwo jest dość podobne do Picassa, ale jest znacznie szybsze niż Picasso” i „Szybownictwo zużywa mniej pamięci niż Picasso”. Niestety nie jestem zadowolony z tych pomysłów, wolę ten link: medium.com/@multidots/glide-vs-picasso-930eed42b81d . Przy okazji, nie mogę teraz przetestować Glide 4.0, ponieważ nie mogę uaktualnić wersji do 3.0.1 (wolne połączenie z Internetem); ale przetestowałem Glide 3.5.2 na gifie, działa, ale nie idealnie, jak się spodziewałem na dużych obrazach (miga), i jest to również częsty problem. Proszę CMIW.
Nguyen Tan Dat
7

Użyj ImageViewEx , biblioteki, która sprawia, że ​​korzystanie z gif jest tak proste, jak korzystanie z ImageView.

NightSkyCode
źródło
To jest przestarzałe
Martin Marconcini
Przejrzałem ten kod bibliotek, powinien być dobry przez około 2 lata.
NightSkyCode
1
Tak, myślę, że to względnie w porządku, po prostu wskazując, że autor postanowił to zrobić. (i dlatego nie utrzymuj go), wskazując, że powinniśmy używać czegoś takiego jak Picasso, co jest dziwne, ponieważ Picasso jest narzędziem do pobierania obrazów i nie pomoże ci, jeśli chodzi o wyświetlanie animowanego gifa, niż jakikolwiek z wielu plików do pobrania / pamięci podręcznej narzędzia tam.
Martin Marconcini,
6

Spróbuj tego, poniżej wyświetlaj kod gif w pasku postępu

loading_activity.xml (w folderze 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 (w folderze wysuwnym)

tutaj umieszczam black_gif.gif (w folderze z możliwością rysowania), możesz tutaj umieścić swój własny 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%" />

ŁadowanieActivity.java (w folderze 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
źródło
Widzę, że obracasz gif. Czemu?
AlikElzin-kilaka
Jak umieścić gif w folderze do rysowania?
Apurva,
6

Nikt nie wspomniał o bibliotece Ion ani Glide . działają bardzo dobrze.

Jest łatwiejszy w obsłudze w porównaniu do WebView.

bafo
źródło
5

Odniosłem sukces dzięki rozwiązaniu zaproponowanemu w tym artykule , zwanej klasą GifMovieView, która renderuje, Viewktórą można następnie wyświetlić lub dodać do określonegoViewGroup . Sprawdź inne metody przedstawione w częściach 2 i 3 określonego artykułu.

Jedyną wadą tej metody jest to, że antyaliasing w filmie nie jest tak dobry (musi to być efekt uboczny korzystania z „podejrzanej” Movieklasy Androida ). Lepiej jest wtedy ustawić tło na jednolity kolor w animowanym pliku GIF.

Dr1Ku
źródło
4

Kilka przemyśleń na temat BitmapDecode ... Zasadniczo wykorzystuje on starożytną, ale raczej pozbawioną cech klasę Movie z android.graphics. W najnowszych wersjach API musisz wyłączyć przyspieszenie sprzętowe, jak opisano tutaj . W przeciwnym razie było to dla mnie dziwne.

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

Oto przykład BitmapDecode skrócony tylko o część GIF. Musisz stworzyć swój własny widżet (Widok) i narysować go sam. Nie tak potężny jak 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();
            }
        }
    }
}

W tym świetnym samouczku można znaleźć 2 inne metody, jedną z ImageView, drugą z WebView . Metoda ImageView wykorzystuje gifview na licencji Apache z Google Code.

lubosz
źródło
1
@luboz czy możesz mi powiedzieć, która metoda jest dobra dla wydajności Androida ... chcę użyć animowanego gif dla paska ładowania ekranu powitalnego. więc możesz zasugerować, która metoda jest lepsza. chcę również wiedzieć, że za pomocą metody widoku obrazu można użyć właściwości typu skali?
Zamień-IOS-Android
4

@PointerNull dał dobre rozwiązanie, ale nie jest idealne. Nie działa na niektórych urządzeniach z dużymi plikami i wyświetla wadliwą animację Gif z ramkami delta w wersji wcześniejszej niż ICS. Znalazłem rozwiązanie bez tych błędów. Jest biblioteką z natywnym dekodowaniem do rysowania: koral-android-gif-drawable .

Siergiej Wasilenko
źródło
2

Umieść go w WebView, musi być w stanie wyświetlać go poprawnie, ponieważ domyślna przeglądarka obsługuje pliki gif. (Froyo +, jeśli się nie mylę)

kluczowiec
źródło
To nie jest prawda. Nie wszystkie przeglądarki obsługują pliki GIF.
RichieHH,
4
Mamy nadzieję, że nie potrzebujemy wszystkich przeglądarek ... Przeglądarka Stock obsługuje ją od Androida 2.2, więc proszę nie głosujcie proszę. WebView z pewnością wyświetli GIF!
keybee
2

Istnieją dwie opcje ładowania animowanych gifów do naszych aplikacji na Androida

1) Za pomocą Glide załaduj gif do pliku 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) Za pomocą html załadować gif do pliku WebView

Utwórz plik HTML z adresem do pliku .gif:

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

zapisz ten plik w katalogu zasobów:

wprowadź opis zdjęcia tutaj

Załaduj ten HTML do WebView aplikacji:

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

Oto pełny przykład tych dwóch opcji .

wprowadź opis zdjęcia tutaj

Jorgesys
źródło
2

Tylko dla Androida API (Android Pie) 28 i +

użyj AnimatedImageDrawable jako

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

Kod XML, dodaj 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 jest dzieckiem Drawable i stworzonym przez ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawableco dodatkowo wymagało wystąpienia ImageDecoder.Sourceutworzonego przez ImageDecoder.createSource.

ImageDecoder.createSourcemoże pobierać źródło tylko jako nazwę, ByteBuffer, Plik, ID zasobu, URI, ContentResolver, aby utworzyć obiekt źródłowy i używa go do utworzenia AnimatedImageDrawablejako Drawable(wywołanie polimorficzne)

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)

Uwaga: Można również utworzyć Bitmapza pomocą ImageDecoder # decodeBitmap .

Wynik:

AnimatedDrawable obsługuje również zmianę rozmiaru, manipulowanie ramkami i kolorami

Pavneet_Singh
źródło
1

Myślę, że lepszą biblioteką do obsługi plików gif jest ta: autor koral

Użyłem go i odnoszę sukces, a ta biblioteka jest poświęcona GIF'om; ale gdzie jako picasso i szybowanie są ramami ogólnego zastosowania ; więc myślę, że twórcy tej biblioteki całkowicie skoncentrowali się na plikach gif

DJphy
źródło
1

Chciałem tylko dodać, że klasa Movie jest teraz przestarzała.

Ta klasa została uznana za przestarzałą na poziomie API P.

Zalecane jest użycie tego

AnimatedImageDrawable

Wyciągany do rysowania animowanych obrazów (takich jak GIF).

Sushobh Nadiger
źródło
1

Utwórz pakiet o nazwie „Utils” w folderze src i utwórz klasę o nazwie „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");
        }
    }
}

Teraz zdefiniuj GifImageView w pliku 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);
    }
}

Teraz plik części interfejsu użytkownika: 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>

Kod zasobu: przykład Androida

Tienanhvn
źródło
jak zmienić rozmiar obrazu, proszę
The Dead Guy
0

Przede wszystkim przeglądarka Android powinna obsługiwać animowane pliki GIF. Jeśli nie, to jest to błąd! Zobacz narzędzia do śledzenia problemów.

Jeśli wyświetlasz te animowane pliki GIF poza przeglądarką, może to być inna historia. Aby zrobić to, o co prosisz, potrzebna będzie zewnętrzna biblioteka, która obsługuje dekodowanie animowanych GIF-ów.

Pierwszym wywołaniem byłoby przyjrzenie się interfejsowi API Java2D lub JAI (Java Advanced Imaging), chociaż byłbym bardzo zaskoczony, gdyby system Android Dalvik obsługiwał te biblioteki w Twojej aplikacji.

Eurig Jones
źródło
niektóre urządzenia nie wyświetlają animowanych gifów, nawet w przeglądarce internetowej. na przykład wiem, że Galaxy Mini z Androidem 2.3.6 ich nie pokazuje.
programista Androida
0

Podobne do tego, co powiedział @Leonti, ale z nieco większą głębią:

Aby rozwiązać ten sam problem, otworzyłem GIMP, ukryłem wszystkie warstwy z wyjątkiem jednej, wyeksportowałem jako własny obraz, a następnie ukryłem tę warstwę i odkryłem następną itd., Dopóki nie miałem osobnych plików zasobów dla każdego . Następnie mógłbym użyć ich jako ramek w pliku XML AnimationDrawable.

Jon O
źródło
1
Możesz użyć gifsicle do wyodrębnienia ramek, jeśli nie masz tyle czasu. Również Python lub Bash są bardzo przydatne podczas generowania plików XML.
lubosz
0

Rozwiązałem to, dzieląc gif na ramki i używając standardowej animacji Androida

Raluca Lucaci
źródło
0

Coś, co zrobiłem, aby wyświetlać gify w aplikacjach. Rozszerzyłem ImageView, aby ludzie mogli swobodnie korzystać z jego atrybutów. Może wyświetlać gify z adresu URL lub z katalogu zasobów. Biblioteka ułatwia także rozszerzanie klas na dziedziczenie po niej i rozszerzanie jej o obsługę różnych metod inicjowania gif.

https://github.com/Gavras/GIFView

Na stronie github znajduje się mały przewodnik.

Został również opublikowany na Android Arsenal:

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

Użyj przykładu:

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

W działalności:

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

        }
});

Programowe ustawianie gif:

mGifView.setGifResource("asset:gif1");
Tzlil Gavra
źródło
0

Najłatwiejszy sposób - można rozważyć poniższy kod

Możemy skorzystać z Imageview setImageResource, zapoznaj się z poniższym kodem.

Poniższy kod może być użyty do pokazania obrazu jak gif incase, jeśli masz wielokrotny podzielony obraz gif. Po prostu podziel gif na pojedyncze png z narzędzia online i umieść obraz w rysunku, jak w poniższej kolejności

image_1.png, image_2.png itp.

Poproś program obsługi o dynamiczną zmianę obrazu.

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);
// 
                    }
                });
              }
Lakszmanan
źródło
0

Prostym sposobem wyświetlania animowanego GIF bezpośrednio z adresu URL do układu aplikacji jest użycie klasy WebView.

Krok 1: W układzie XML

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

Krok 2: W swojej działalności

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

Krok 3: W swoim pliku Manifest.XML dokonaj pozwolenia na dostęp do Internetu

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

Krok 4: Jeśli chcesz ustawić przezroczystość tła GIF i dopasować GIF do swojego układu

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

Ovais Chaudhry
źródło
Dzięki za obejście tego problemu, ale znaczny deweloper może nie chcieć mieć renderowania
nienatywnego z
-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
źródło