Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Анимированный GIF

Android не поддерживает анимированные gif-файлы из коробки. Рассмотрим несколько способов для решения проблемы.

В Android 9.0 (API 28) наконец-то появилась поддержка анимированных GIF и WEBP

Первое, что приходит в голову - использовать WebView. Можно просто разместить на экране своей активности компонент и загрузить в него нужную картинку.

Второй вариант - создать свой новый класс с собственным конструктором, унаследовавшись от WebView:


package ru.alexanderklimov.test;

import android.content.Context;
import android.webkit.WebView;

public class GifWebView extends WebView {

	public GifWebView(Context context, String path) {
		super(context);
		loadUrl(path);
	}
}

Осталось только программно установить созданный компонент. Для опытов использовался файл lick.gif в папке assets.


@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	GifWebView gifWebView = new GifWebView(this,
			"file:///android_asset/lick.gif");
	setContentView(gifWebView);

}

Два способа идентичны по сути. Но следует учесть, что WebView является очень "тяжёлым" компонентом, практически это целый браузер. Но с другой стороны, это самый просто и понятный способ.

Movie

Альтернативный способ показать анимированный файл - воспользоваться классом android.graphics.Movie. Создадим новый класс MoviewGifView:


package ru.alexanderklimov.test;

import java.io.InputStream;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Movie;
import android.os.SystemClock;
import android.view.View;

public class MovieGifView extends View {

	private Movie mMovie;
	private InputStream mStream;
	private long mMoviestart;

	public MovieGifView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public MovieGifView(Context context, InputStream stream) {
		super(context);

		mStream = stream;
		mMovie = Movie.decodeStream(mStream);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawColor(Color.TRANSPARENT);
		super.onDraw(canvas);
		final long now = SystemClock.uptimeMillis();
		if (mMoviestart == 0) {
			mMoviestart = now;
		}
		final int relTime = (int) ((now - mMoviestart) % mMovie.duration());
		mMovie.setTime(relTime);
		mMovie.draw(canvas, 20, 20);
		this.invalidate();
	}
}

Подключаем в главной активности.


@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	InputStream stream = null;
	try {
		stream = getAssets().open("lick.gif");
	} catch (IOException e) {
		e.printStackTrace();
	}
	MovieGifView gifView = new MovieGifView(this, stream);
	setContentView(gifView);
}

Желательно также отключить поддержку аппаратного ускорения у активности в манифесте.


<activity
    android:name=".MainActivity"
    android:hardwareAccelerated="false"
    android:label="@string/app_name" >

Пример простой и работоспособный.

Можно доработать класс MovieGifView, добавив поддержку загрузки из ресурсов и управление размерами.


package ru.alexanderklimov.test;

import java.io.InputStream;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Movie;
import android.os.SystemClock;
import android.view.View;

public class MovieGifView extends View {

	private Movie mMovie;
	private InputStream mStream;
	private long mMoviestart;
	private int mMovieWidth, mMovieHeight;
	private long mMovieDuration;

	public MovieGifView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public MovieGifView(Context context, InputStream stream) {
		super(context);

		mStream = stream;
		mMovie = Movie.decodeStream(mStream);

		mMovieWidth = mMovie.width();
		mMovieHeight = mMovie.height();
		mMovieDuration = mMovie.duration();
	}

	public MovieGifView(Context context, int resId) {
		super(context);

		InputStream stream = context.getResources().openRawResource(resId);

		mMovie = Movie.decodeStream(stream);
		mMovieWidth = mMovie.width();
		mMovieHeight = mMovie.height();
		mMovieDuration = mMovie.duration();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(mMovieWidth, mMovieHeight);
	}

	public int getMovieWidth() {
		return mMovieWidth;
	}

	public int getMovieHeight() {
		return mMovieHeight;
	}

	public long getMovieDuration() {
		return mMovieDuration;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawColor(Color.TRANSPARENT);
		super.onDraw(canvas);
		final long now = SystemClock.uptimeMillis();
		if (mMoviestart == 0) {
			mMoviestart = now;
		}

		final int relTime = (int) ((now - mMoviestart) % mMovie.duration());
		mMovie.setTime(relTime);
		mMovie.draw(canvas, 0, 0);
		this.invalidate();
	}
}

Добавим вывод логов.


MovieGifView gifView = new MovieGifView(this, R.drawable.lick);
setContentView(gifView);

String stringInfo = "";
stringInfo += "Duration: " + gifView.getMovieDuration() + "\n";
stringInfo += "W x H: " + gifView.getMovieWidth() + " x "
		+ gifView.getMovieHeight() + "\n";
Log.i("gif", stringInfo);

Дополнительное чтение

Существуют разные библиотеки для работы с анимированными гифками.

Cutta/GifView: Library for playing gifs on Android.
GitHub - koral--/android-gif-drawable: Views and Drawable for displaying animated GIFs on Android

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

Посмотрите другие примеры:
Android-er: Play animated GIF using android.graphics.Movie, with Movie.decodeStream(InputStream)
Android-er: Play animated GIF using android.graphics.Movie, with Movie.decodeByteArray(InputStream)
Android-er: Animated GIF: load attribute resource of android:src in XML
Android-er: Load animated GIF from Internet

Библиотека Glide для работы с изображениями поддерживает GIF. Наверное, это лучший вариант для ваших проектов.

Реклама