Показать анимированный GIF
Я хочу отображать анимированные GIF-изображения в моем приложении. Как я выяснил, сложный способ, которым Android не поддерживает анимированный GIF изначально.
Однако он может отображать анимацию с помощью AnimationDrawable:
Разработка> Руководства> Изображения и графика> Обзор Drawables
В примере используется анимация, сохраненная в виде кадров в ресурсах приложения, но мне нужно отобразить анимированный GIF-файл напрямую.
Мой план состоит в том, чтобы разбить анимированный GIF на кадры и добавить каждый кадр как нарисованный в AnimationDrawable.
Кто-нибудь знает, как извлечь кадры из анимированного GIF и конвертировать каждый из них в Drawable?
32 ответа
Android фактически может декодировать и отображать анимированные GIF-файлы, используя класс android.graphics.Movie.
Это не слишком документировано, но есть в SDK Reference. Более того, он используется в примерах в ApiDemos в примере BitmapDecode с некоторым анимированным флагом.
ОБНОВИТЬ:
Используйте скольжение:
dependencies {
implementation 'com.github.bumptech.glide:glide:4.0.0'
}
использование:
Glide.with(context).load(GIF_URI).into(new GlideDrawableImageViewTarget(IMAGE_VIEW));
см документы
Также поместите (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
Вот и все, я надеюсь, вы поможете.
Я решил проблему, разделив gif- анимацию на кадры перед сохранением в телефоне, поэтому мне не пришлось бы иметь дело с этим в Android.
Затем я загружаю каждый кадр в телефон, создаю из него Drawable, а затем создаю AnimationDrawable - очень похоже на пример из моего вопроса.
Я нашел очень простой способ, с хорошим и простым рабочим примером здесь
отображать анимированный виджет
Прежде чем заставить его работать, в коде необходимо выполнить некоторые действия.
В СЛЕДУЮЩИХ
@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) {
по названию класса...
после внесения этих небольших изменений все должно работать как у меня...
надеюсь, это поможет
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);
}
});
Способы показать анимированный GIF на Android:
- Кино класс. Как уже упоминалось выше, это довольно глючно.
- WebView. Он очень прост в использовании и обычно работает. Но иногда это начинает плохо себя вести, и это всегда на некоторых неясных устройствах, которых у вас нет. Кроме того, вы не можете использовать несколько экземпляров в любом виде списка, потому что это влияет на вашу память. Тем не менее, вы можете рассматривать это как основной подход.
- Пользовательский код для декодирования GIF-файлов в растровые изображения и отображения их как Drawable или ImageView. Я упомяну две библиотеки:
https://github.com/koral--/android-gif-drawable - декодер реализован на C, поэтому он очень эффективен.
https://code.google.com/p/giffiledecoder - декодер реализован на Java, поэтому с ним проще работать. Все еще достаточно эффективно, даже с большими файлами.
Вы также найдете много библиотек, основанных на классе GifDecoder. Это также Java-декодер, но он работает, загружая весь файл в память, поэтому он применим только к маленьким файлам.
Мне было очень тяжело работать с анимацией в Android. У меня были только следующие две работы:
- WebView
- ион
WebView работает нормально и действительно просто, но проблема в том, что он замедляет загрузку представления, и приложение не отвечает на секунду или около того. Мне это не понравилось. Поэтому я пробовал разные подходы (НЕ РАБОТАЛ):
- ImageViewEx устарела!
- Пикассо не загружал анимированный GIF
- http://android-gif-drawable/ выглядит великолепно, но это вызвало некоторые проблемы с проводным NDK в моем проекте. Это привело к тому, что моя локальная библиотека NDK перестала работать, и я не смог это исправить
Я имел некоторые взад и вперед с Ion
; Наконец, у меня это работает, и это действительно быстро:-)
Ion.with(imgView)
.error(R.drawable.default_image)
.animateGif(AnimateGifMode.ANIMATE)
.load("file:///android_asset/animated.gif");
Glide
Библиотека загрузчиков изображений для Android, рекомендованная Google.
- Glide очень похож на Picasso, но это намного быстрее, чем Picasso.
- Glide потребляет меньше памяти, чем Picasso.
Что у этого Glide есть, но у Пикассо нет
Возможность загрузки GIF-анимации в простой ImageView может быть самой интересной особенностью Glide. И да, вы не можете сделать это с Пикассо. Некоторые важные ссылки
Попробуйте это, приведенный ниже код отображения 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);
}
}
Используйте ImageViewEx, библиотеку, которая делает использование GIF столь же простым, как использование ImageView
,
У меня был успех с решением, предложенным в этой статье, класс под названием GifMovieView
, который оказывает View
которые затем могут быть отображены или добавлены к конкретному ViewGroup
, Ознакомьтесь с другими методами, представленными в частях 2 и 3 указанной статьи.
Единственным недостатком этого метода является то, что сглаживание в фильме не так уж и хорошо (должно быть побочным эффектом использования "теневого" Android Movie
Учебный класс). Тогда вам лучше установить сплошной цвет фона в анимированном GIF.
Некоторые мысли по поводу примера 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.
@PointerNull дал хорошее решение, но оно не идеально. Он не работает на некоторых устройствах с большими файлами и показывает некорректную анимацию Gif с дельта-кадрами в предыдущей версии ICS. Я нашел решение без этих ошибок. Это библиотека с собственным декодированием для рисования: https://github.com/koral--/android-gif-drawable.
Только для 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 также поддерживает изменение размера, рамку и управление цветом
Поместите его в WebView, он должен отображать его правильно, так как браузер по умолчанию поддерживает файлы GIF. (Froyo+, если я не ошибаюсь)
Создайте пакет с именем "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);
}
}
Теперь файл части пользовательского интерфейса: 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
Существует два варианта загрузки анимированных 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");
Я думаю, что лучшая библиотека для работы с GIF-файлами : koral
Использовал его, и я успешен, и эта библиотека посвящена GIF'S; но где как Пикассо и скольжение являются основой изображения общего назначения; так что я думаю, что разработчики этой библиотеки полностью сосредоточились на gif-файлах
Просто хотел добавить, что класс Movie теперь устарел.
Этот класс устарел на уровне API P.
Рекомендуется использовать это
Drawable для рисования анимированных изображений (например, GIF).
Используйте фреску. Вот как это сделать:
http://frescolib.org/docs/animations.html
Вот репо с образцом:
https://github.com/facebook/fresco/tree/master/samples/animation
Осторожно, фреска не поддерживает перенос содержимого!
Самый простой способ - можно рассмотреть приведенный ниже код
Мы можем воспользоваться 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);
//
}
});
}
Я решил это, разделив gif на кадры и используя стандартную анимацию Android
Подобно тому, что сказал @Leonti, но с большей глубиной:
Чтобы решить ту же проблему, я открыл GIMP, скрыл все слои, кроме одного, экспортировал его как свое собственное изображение, а затем скрыл этот слой и отобразил следующий, и т. Д., Пока у меня не было отдельных файлов ресурсов для каждого из них., Затем я мог бы использовать их в качестве фреймов в XML-файле AnimationDrawable.
Что-то, что я сделал для показа картинок в приложениях. Я расширил ImageView, чтобы люди могли свободно использовать его атрибуты. Это может показать GIF-файлы из 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");
Для экономии ресурсов существует библиотека glide для файлов. Понятия не имею, зачем использовать что-то еще, особенно веб-просмотр, чтобы показывать только изображение.Glide - идеальная и простая библиотека, которая подготавливает анимированные рисунки из gif и помещает их прямо в просмотр изображений. Сама логика анимации ручки gifdrawable.Gif имеют внутри lzw заархивированные необработанные данные rgb анимации. Нет причин для сложного использования веб-просмотра и управления большим количеством файлов, чтобы отображать только файл gif в приложении.
Если вы хотите использовать Glide для загрузки gif:
Glide.with(this)
.asGif()
.load(R.raw.onboarding_layers) //Your gif resource
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE))
.listener(new RequestListener<GifDrawable>() {
@Override
public boolean onLoadFailed(@Nullable @org.jetbrains.annotations.Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
resource.setLoopCount(1);
return false;
}
})
.into((ImageView) view.findViewById(R.id.layer_icons));
Простой способ отобразить анимированный 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);
Вы можете использовать библиотеку GifAnimationDrawable, которая находится по этой ссылке - https://github.com/Hipmob/gifanimateddrawable, и которая преобразует любой gif в AnimationDrawable. Наслаждаться:)