Показать анимированный GIF

261

Я хочу отображать анимированные GIF-изображения в моем приложении. Как я выяснил, сложный способ, которым Android не поддерживает анимированный GIF изначально.

Однако он может отображать анимацию, используя AnimationDrawable :

Разработка> Руководства> Изображения и графика> Обзор Drawables

В примере используется анимация, сохраненная в виде кадров в ресурсах приложения, но мне нужно отобразить анимированный GIF-файл напрямую.

Мой план состоит в том, чтобы разбить анимированный GIF на кадры и добавить каждый кадр как нарисованный в AnimationDrawable.

Кто-нибудь знает, как извлечь кадры из анимированного GIF и преобразовать каждый из них в Drawable ?

Леонтий
источник
3
Ты имеешь ввиду в андроиде или извлечение кадров из gif с помощью внешнего инструмента?
Осмунд
это определенно ошибка, см. IssueTracker для получения дополнительной информации.
fbtb
Просто для всех тех, кто пришел сюда в поисках приложения, которое может отображать анимированные GIF-файлы: quickPic
rubo77
Используйте фреску для отображения GIF github.com/facebook/fresco Я думаю, что это простое решение.
kaitian521

Ответы:

191

Android фактически может декодировать и отображать анимированные GIF-файлы, используя класс android.graphics.Movie.

Это не слишком задокументировано, но есть в SDK Reference . Кроме того, он используется в примерах в ApiDemos в примере BitmapDecode с некоторым анимированным флагом.

Указатель Нуль
источник
9
Насколько это стабильно? Я реализовал это в своем приложении, на моем устройстве Ice Cream Sandwich оно вообще не работает, на эмуляторе 2.3 оно работает, но некоторые кадры GIF содержат ошибки (неправильные цвета). На компьютере это, конечно, работает нормально. Что дает?
Бенуа Даффес
12
@Bicou На устройствах после HC вы должны setLayerType(LAYER_TYPE_SOFTWARE)на вашем View. Но это все еще работает только для некоторых картинок и некоторых устройств.
Михал К
9
@ MichałK Спасибо! Paint p = new Paint(); p.setAntiAlias(true); setLayerType(LAYER_TYPE_SOFTWARE, p);работал!
Хлоя
1
@lubosz: LAYER_TYPE_SOFTWARE должно быть достаточно для установки.
Указатель нулевой
2
Класс фильма специально не задокументирован - он слабый и не поддерживается. Если вам нужны правильные анимации Gif, вам лучше реализовать их самостоятельно. Я сделал это для своего приложения, используя NDK.
Указатель нулевой
60

ОБНОВИТЬ:

Используйте скольжение:

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

использование:

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

см документы

itzhar
источник
1
Мне кажется, теперь все в порядке, очевидно, ответ не может включать в себя всю библиотеку, поэтому пример вызова кажется достаточным.
Габорист
@gaborous Очевидно, что код не был включен во время пометки.
Янв
1
Я не рекомендую использовать эту библиотеку, если вы уже используете NDK. После добавления этой библиотеки в gradle модуль Unity перестал работать.
РоминаВ
Это лучшая библиотека, которую я нашел. Одна вещь, в которой я застрял - это реализация пинча для увеличения изображения в формате gif. Кто-нибудь знает?
Вайпер
28

также поместите (main / assets / htmls / name.gif) [с помощью этого html-файла подгоните к размеру]

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

объявите в своем XML, например, так (main / res / layout / name.xml): [вы определяете размер, например]

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

в вашей деятельности поместите следующий код внутри onCreate

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

если вы хотите загружать динамически, вы должны загрузить веб-представление с данными:

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

предложение: лучше загрузить GIF со статическими изображениями для получения дополнительной информации проверьте https://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

Вот и все, я надеюсь, вы поможете.

Алекс Зараос
источник
2
Если я хочу загрузить GIF из SDCard?
Джайдев
если вы хотите загрузить с sdcard: замените «file: ///android_asset/htmls/name.html» на URI вашего изображения
Alex Zaraos
Используя этот метод, как я могу динамически изменить имя файла GIF? Я не хочу, чтобы html-файл соответствовал каждому GIF-файлу, который мне нужно отображать в моем приложении
scrayne
Webview для GIF?!? Вы думали о производительности, потреблении памяти и батареи?
Дуна
@Duna, которая была 5 лет назад, в настоящее время мы можем использовать, например, скольжение
Alex Zaraos
22

Я решил проблему, разделив gif- анимацию на кадры перед сохранением в телефоне, поэтому мне не пришлось бы иметь дело с этим в Android.

Затем я загружаю каждый кадр в телефон, создаю из него Drawable, а затем создаю AnimationDrawable - очень похоже на пример из моего вопроса.

Леонтий
источник
2
Какой документированный способ обработки анимации.
RichieHH
16

я нашел очень простой способ, с хорошим и простым рабочим примером здесь

отображать анимированный виджет

Прежде чем заставить его работать, в коде необходимо выполнить некоторые действия.

В СЛЕДУЮЩИХ

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

просто замени

setContentView(new MYGIFView());

в

setContentView(new MYGIFView(this));

И В

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

Предоставьте свой собственный файл анимации GIF

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

ЗАМЕНА ПЕРВОЙ ЛИНИИ В

public MYGIFView(Context context) {

по названию класса ...

после внесения этих небольших изменений все должно работать как у меня ...

надеюсь, это поможет

Apperside
источник
2
На какой версии андроид вы пробовали это? Я пробовал на Android версии 2.2 и 2.3, но он возвращает объект фильма ноль. Есть идеи, что может быть не так?
Ашвини Шахапуркар
16
Пожалуйста, очистите этот ответ, это так, случайно.
Taxeeta
2
в чем проблема с ответом? Я просто предоставил ссылку и некоторые необходимые исправления, чтобы она
заработала
10

Способы показать анимированный GIF на Android:

  • Кино класс. Как уже упоминалось выше, это довольно глючно.
  • WebView. Он очень прост в использовании и обычно работает. Но иногда это начинает плохо себя вести, и это всегда на некоторых неясных устройствах, которых у вас нет. Кроме того, вы не можете использовать несколько экземпляров в любом виде списка, потому что это влияет на вашу память. Тем не менее, вы можете рассматривать это как основной подход.
  • Пользовательский код для декодирования GIF-файлов в растровые изображения и отображения их как Drawable или ImageView. Я упомяну две библиотеки:

https://github.com/koral--/android-gif-drawable - декодер реализован на C, поэтому он очень эффективен.

https://code.google.com/p/giffiledecoder - декодер реализован на Java, поэтому с ним проще работать. Все еще достаточно эффективно, даже с большими файлами.

Вы также найдете много библиотек, основанных на классе GifDecoder. Это также Java-декодер, но он работает, загружая весь файл в память, поэтому он применим только к маленьким файлам.

Ник Фролов
источник
10

Мне было очень тяжело работать с анимацией в Android. У меня были только следующие две работы:

  1. WebView
  2. ион

WebView работает нормально и действительно легко, но проблема в том, что он замедляет загрузку, и приложение не отвечает на секунду или около того. Мне это не понравилось. Поэтому я пробовал разные подходы (НЕ РАБОТАЛ):

  1. ImageViewEx устарела!
  2. Пикассо не загружал анимированный GIF
  3. android-gif-drawable выглядит великолепно, но это вызвало некоторые проблемы с NDK в моем проекте. Это привело к тому, что моя локальная библиотека NDK перестала работать, и я не смог это исправить

У меня были некоторые взад и вперед Ion; Наконец, у меня это работает, и это действительно быстро :-)

Ion.with(imgView)
  .error(R.drawable.default_image)
  .animateGif(AnimateGifMode.ANIMATE)
  .load("file:///android_asset/animated.gif");
Roozbeh Zabihollahi
источник
У меня были те же проблемы с NDK, что и у android-gif-drawable.
РоминаВ
Здравствуйте @RominaV, Вы использовали индикатор выполнения в Ion при загрузке GIF, потому что мне нужно показать прогресс при загрузке GIF.
patel135
9

Glide 4.6

1. Загрузить gif

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

2. Получить файл объекта

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

Библиотека загрузчиков изображений для Android, рекомендованная Google.

  • Glide очень похож на Picasso, но это намного быстрее, чем Picasso.
  • Glide потребляет меньше памяти, чем Picasso.

Что есть у Glide, но у Пикассо нет

Возможность загрузки GIF-анимации в простой ImageView может быть самой интересной особенностью Glide. И да, вы не можете сделать это с Пикассо. Некоторые важные ссылкивведите описание изображения здесь

  1. https://github.com/bumptech/glide
  2. http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
Shoeb Siddique
источник
Где Google рекомендует Glid?
Derzu
1
Посмотрите, где команда разработчиков Android использовала Glide в своем примере приложения. developer.android.com/samples/XYZTouristAttractions/Application/...
Shoeb Сиддик
1
«Glide очень похож на Picasso, но это намного быстрее, чем Picasso» и «Glide потребляет меньше памяти, чем Picasso». Извините, я не доволен этими идеями, пожалуйста, предпочтите эту ссылку: medium.com/@multidots/glide-vs-picasso-930eed42b81d . Кстати, я не могу сейчас протестировать Glide 4.0 из-за невозможности обновить сборку до 3.0.1 (медленное интернет-соединение); но я протестировал Glide 3.5.2 на показе gif, он работает, но не совсем так, как я ожидал на большом img (он мерцает), и это тоже общая проблема. Пожалуйста, CMIW.
Нгуен Тан Дат
7

Используйте ImageViewEx , библиотеку, которая делает использование GIF столь же простым, как использование ImageView.

NightSkyCode
источник
Это устарело
Мартин Маркончини
Я просмотрел код этой библиотеки, он должен быть хорош в течение 2 или более лет.
NightSkyCode
1
Да, я думаю, что это относительно хорошо, просто подчеркивая, что автор решил осудить это. (и, следовательно, не поддерживать его), указывая на то, что мы должны использовать что-то вроде Picasso, что странно, потому что Picasso является загрузчиком изображений и не поможет вам, когда дело доходит до отображения анимированного GIF больше, чем любой из множества закачек / кеша инструменты там.
Мартин Маркончини,
6

Попробуйте это, приведенный ниже код отображения GIF-файла в ProgressBar

loading_activity.xml (в папке Layout)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff" >

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/custom_loading"
        android:visibility="gone" />

</RelativeLayout>

custom_loading.xml (в папке для рисования)

здесь я положил black_gif.gif (в папке drawable), вы можете поместить свой собственный GIF здесь

<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/black_gif"
    android:pivotX="50%"
    android:pivotY="50%" />

LoadingActivity.java (в папке res)

public class LoadingActivity extends Activity {

    ProgressBar bar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_loading);
        bar = (ProgressBar) findViewById(R.id.progressBar);
        bar.setVisibility(View.VISIBLE);

    }

}
Нирав Калола
источник
Я вижу, вы вращаете GIF. Зачем?
Алик Эльзин-килака
Как вы можете положить GIF в папку для рисования?
Апурва
6

Никто не упомянул библиотеку Ion или Glide . они работают очень хорошо.

Это проще в обращении по сравнению с WebView.

bapho
источник
5

У меня был успех с решением, предложенным в этой статье , классом GifMovieView, который отображает, Viewкоторый затем может быть отображен или добавлен к конкретному ViewGroup. Ознакомьтесь с другими методами, представленными в частях 2 и 3 указанной статьи.

Единственный недостаток этого метода заключается в том, что сглаживание в фильме не так уж хорошо (должно быть побочным эффектом использования «теневого» Movieкласса Android ). Тогда вам лучше установить сплошной цвет фона в анимированном GIF.

Dr1Ku
источник
4

Некоторые мысли по поводу примера BitmapDecode ... В основном он использует древний, но довольно безликий класс Movie из android.graphics. В последних версиях API вам необходимо отключить аппаратное ускорение, как описано здесь . В противном случае это было для меня

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

Вот пример BitmapDecode, сокращенный только с частью GIF. Вы должны сделать свой собственный виджет (вид) и нарисовать его самостоятельно. Не так мощно, как 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();
            }
        }
    }
}

2 других метода, один с ImageView, другой с WebView, можно найти в этом прекрасном руководстве . Метод ImageView использует лицензированный Apache android-gifview из Google Code.

lubosz
источник
1
@luboz Подскажите, пожалуйста, какой метод хорош для производительности Android ... Я хочу использовать анимированный GIF для панели загрузки заставки. поэтому можете ли вы предложить, какой метод лучше. Также я хочу знать, что с помощью метода просмотра изображений можно использовать свойство типа масштаба?
своп-IOS-Android
4

@PointerNull дал хорошее решение, но оно не идеально. Он не работает на некоторых устройствах с большими файлами и показывает некорректную анимацию Gif с дельта-кадрами в предварительной версии ICS. Я нашел решение без этих ошибок. Это библиотека с собственным декодированием для рисования : koral's android-gif-drawable .

Сергей Василенко
источник
2

Поместите его в WebView, он должен отображать его правильно, поскольку браузер по умолчанию поддерживает файлы GIF. (Froyo +, если я не ошибаюсь)

keybee
источник
Это неправда. Не все браузеры поддерживают GIF.
RichieHH
4
Надеюсь, нам не нужны все браузеры ... Стандартный браузер поддерживает его начиная с Android 2.2, так что, пожалуйста, не отрицайте меня. WebView определенно будет отображать GIF!
Кейби
2

Существует два варианта загрузки анимированных GIF-файлов в наши приложения для Android

1) Использование Glide для загрузки GIF в 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) Использование HTML для загрузки GIF в WebView

Создайте HTML с адресом .gif файла:

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

сохраните этот файл в каталоге активов:

введите описание изображения здесь

Загрузите этот HTML-код в WebView вашего приложения:

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

Вот полный пример этих двух вариантов .

введите описание изображения здесь

Jorgesys
источник
2

Только для Android API (Android Pie) 28 и +

использовать AnimatedImageDrawable как

// 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-код, добавьте 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 является дочерью Drawable и создан ImageDecoder.decodeDrawable

ImageDecoder.decodeDrawableчто дополнительно требует экземпляр ImageDecoder.Sourceсоздан ImageDecoder.createSource.

ImageDecoder.createSourceможет принимать источник только как имя, ByteBuffer, File, resourceId, URI, ContentResolver для создания исходного объекта и использует его для создания AnimatedImageDrawableкак Drawable(полиморфный вызов)

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)

Примечание: вы также можете создать Bitmapс помощью ImageDecoder # decodeBitmap .

Вывод:

AnimatedDrawable также поддерживает изменение размера, рамку и управление цветом

Pavneet_Singh
источник
1

Я думаю, что лучшая библиотека для обработки GIF-файлов : koral

Использовал его, и я успешен, и эта библиотека посвящена GIF'S; но где как Пикассо и скольжение являются основой изображения общего назначения ; так что я думаю, что разработчики этой библиотеки полностью сосредоточились на gif-файлах

DJphy
источник
1

Просто хотел добавить, что класс Movie теперь устарел.

Этот класс устарел на уровне API P.

Рекомендуется использовать это

AnimatedImageDrawable

Drawable для рисования анимированных изображений (например, GIF).

Сушобх Надигер
источник
1

Создайте пакет с именем «Utils» в папке src и создайте класс с именем «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");
        }
    }
}

Теперь определите GifImageView в файле 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);
    }
}

Теперь UI Part File: 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>

Код ресурса: пример Android

Tienanhvn
источник
как изменить размер изображения, пожалуйста
The Dead Guy
0

Прежде всего, браузер Android должен поддерживать анимированные GIF-файлы. Если это не так, то это ошибка! Посмотрите на проблемы трекеров.

Если вы отображаете эти анимированные GIF-изображения вне браузера, это может быть другой историей. Чтобы сделать то, что вы просите, потребуется внешняя библиотека, которая поддерживает декодирование анимированных GIF-файлов.

Первым портом вызова было бы посмотреть на API Java2D или JAI (Java Advanced Imaging), хотя я был бы очень удивлен, если бы Android Dalvik поддерживал эти библиотеки в вашем приложении.

Эуриг Джонс
источник
некоторые устройства не показывают анимированные GIF-файлы, даже в веб-браузере. в качестве примера я знаю, что galaxy mini с android 2.3.6 их не показывает.
Android-разработчик
0

Подобно тому, что сказал @Leonti, но с большей глубиной:

Чтобы решить ту же проблему, я открыл GIMP, скрыл все слои, кроме одного, экспортировал его как свое собственное изображение, а затем скрыл этот слой и отобразил следующий, и т. Д., Пока у меня не было отдельных файлов ресурсов для каждого из них. , Затем я мог бы использовать их в качестве фреймов в XML-файле AnimationDrawable.

Джон О
источник
1
Вы можете использовать gifsicle, чтобы извлечь кадры, если у вас не так много времени. Также Python или Bash очень удобны при создании XML-файлов.
Любош
0

Я решил это, разделив GIF по кадрам и использовать стандартную анимацию Android

Ралука Лукач
источник
0

Что-то, что я сделал для показа картинок в приложениях. Я расширил ImageView, чтобы люди могли свободно использовать его атрибуты. Он может отображать картинки из URL или из каталога активов. Библиотека также позволяет расширяемым классам наследовать от нее и расширять ее для поддержки различных методов инициализации gif.

https://github.com/Gavras/GIFView

На странице github есть небольшое руководство.

Также было опубликовано на Android Arsenal:

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

Пример использования:

Из 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" />

В деятельности:

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

        }
});

Установка gif программно:

mGifView.setGifResource("asset:gif1");
Цлиль Гавра
источник
0

Самый простой способ - можно рассмотреть приведенный ниже код

Мы можем воспользоваться Imageview setImageResource, см. Ниже код для того же.

Приведенный ниже код может быть использован для показа изображения в формате GIF, если у вас есть несколько изображений GIF. Просто разделите GIF-файл на отдельный PNG-файл из онлайн-инструмента и поместите изображение в рисунок, как показано ниже

image_1.png, image_2.png и т. д.

Есть обработчик для динамического изменения изображения.

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

Простой способ отобразить анимированный GIF непосредственно из URL в макет вашего приложения - использовать класс WebView.

Шаг 1: в вашем макете XML

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

Шаг 2: в вашей деятельности

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

Шаг 3: В вашем Manifest.XML сделайте интернет-разрешение

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

Шаг 4. Если вы хотите, чтобы ваш GIF-фон был прозрачным и чтобы GIF-файл соответствовал вашему макету

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

Овайс Чаудхри
источник
Спасибо за обходной путь, но значительный разработчик может не захотеть использовать не собственный рендеринг из-за некоторых последствий, таких как влияние памяти, использование процессора и время работы от батареи
ruX
-1

Вы можете использовать библиотеку GifAnimationDrawable, которая находится по этой ссылке - https://github.com/Hipmob/gifanimateddrawable , и которая преобразует любой gif в AnimationDrawable. Наслаждаться :)

david72
источник
-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());

      }
    }
  }
}
Ашок Домадия
источник