我想在Android应用程序中显示动画GIF图像,如下图所示。我尝试过webview但没有成功。如何在应用程序中显示动画gif?
答案 0 :(得分:29)
您也可以使用此lib轻松支持gifDrawable。
只需使用GifImageView而不是普通的ImageView:
<pl.droidsonroids.gif.GifImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/your_anim"/>
并在src attr下找到你的gif文件。这就是全部!
答案 1 :(得分:17)
您可以使用Glide:
ImageView imageView = (ImageView) findViewById(R.id.imageView);
GlideDrawableImageViewTarget imageViewTarget = new GlideDrawableImageViewTarget(imageView);
Glide.with(this).load(R.raw.sample_gif).into(imageViewTarget);
答案 2 :(得分:8)
经过长时间的Google搜索,我知道GIF图片没有原生支持。在应用程序中显示动画gif没有适当的解决方案。您可以查看This solution
使布局中的动画gif播放。
答案 3 :(得分:4)
在Android中显示GIF图像的最佳和最简单的解决方案 它会完美地运作:
打开布局文件夹并将此代码放在要显示GIF图像的位置: e-g activity_main.xml
<pl.droidsonroids.gif.GifImageView
android:layout_width="150dp"
android:layout_height="wrap_content"
android:src="@drawable/your_gif_file_name"/>
android:src =“@ drawable / your_gif_file_name”,将'your_gif_file_name'替换为您想要的gif图像文件
答案 4 :(得分:2)
您不需要任何库,只需使用此代码:
第1步: 创建一个名为GIFView.java的文件
package com.thigale.testproject;
/**
* Created by Thigale Sameer on 11-12-16.
*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Movie;
import android.util.AttributeSet;
import android.view.View;
import java.io.InputStream;
public class GifView extends View {
public Movie mMovie;
public long movieStart;
private int gifId;
public GifView(Context context) {
super(context);
}
public GifView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeView(attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "src", 0));
}
public GifView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initializeView(attrs.getAttributeResourceValue("http://schemas.android.com/apk/res-auto", "src", 0));
}
private void initializeView(final int id) {
InputStream is = getContext().getResources().openRawResource(id);
mMovie = Movie.decodeStream(is);
this.gifId = id;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
super.onDraw(canvas);
long now = android.os.SystemClock.uptimeMillis();
if (movieStart == 0) {
movieStart = now;
}
if (mMovie != null) {
int relTime = (int) ((now - movieStart) % mMovie.duration());
mMovie.setTime(relTime);
mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight() - mMovie.height());
this.invalidate();
}
}
public void setGIFResource(int resId) {
this.gifId = resId;
initializeView(this.gifId);
}
public int getGIFResource() {
return this.gifId;
}
}
第2步: 在res / attrs.xml中添加以下行
<declare-styleable name="GIFView">
<attr name="src" format="reference" />
</declare-styleable>
第3步: 在特定活动中添加此行AndroidManifest.xml
android:hardwareAccelerated="false"
第4步: 在XML中创建此视图:
<com.thigale.testproject.GifView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
components:src="@drawable/loading" />
第5步 在创建视图的父活动中,添加以下行:
xmlns:components="http://schemas.android.com/apk/res-auto"
答案 5 :(得分:1)
我也尝试过这样做,但Android并没有使用动画显示gif图像。如果你想达到同样的效果,那么你可以拍摄动画图像的几帧,然后使用逐帧动画。
您可以在以下链接中参考。 http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
答案 6 :(得分:0)
尝试这种方式:
Movie movie,movie1;
InputStream is=null,is1=null;
long moviestart;
long moviestart1;
public GIFView(Context context) {
super(context);
is=context.getResources().openRawResource(R.drawable.hxps);
is1=context.getResources().openRawResource(R.drawable.cartoon);
movie=Movie.decodeStream(is);
movie1=Movie.decodeStream(is1);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFCCCCCC);
super.onDraw(canvas);
long now=android.os.SystemClock.uptimeMillis();
System.out.println("now="+now);
if (moviestart == 0) { // first time
moviestart = now;
}
if(moviestart1==0)
{
moviestart1=now;
}
System.out.println("\tmoviestart="+moviestart);
int relTime = (int)((now - moviestart) % movie.duration()) ;
int relTime1=(int)((now - moviestart1)% movie1.duration());
System.out.println("time="+relTime+"\treltime="+movie.duration());
movie.setTime(relTime);
movie1.setTime(relTime1);
movie.draw(canvas,0,0);
movie1.draw(canvas,10,300);
this.invalidate();
}
答案 7 :(得分:0)
您可以尝试使用此库GifImageView。它非常简单易用。以下示例代码来自此项目的README。
@覆盖 protected void onCreate(final Bundle savedInstanceState){ super.onCreate(savedInstanceState);
gifView = new GifImageView(context); gifView.setBytes(bitmapData); setContentView(gifView);
}
@覆盖 protected void onStart(){ super.onStart(); gifView.startAnimation(); }
@覆盖 protected void onStop(){ super.onStop(); gifView.stopAnimation(); }
答案 8 :(得分:0)
<强>更新强>
android arsenal和GIFView的GitHub页面上有最新版本。
当有人让我帮他展示GIF时,我做的很小。 我在网上找到的大多数东西都是第三方库和解决方案,它们使用UI线程来处理我在手机上运行得不好的gif,所以我决定在android的帮助下自己做这件事。 s电影API。 我特意让它扩展了ImageView,所以我们可以使用scaleType之类的属性。 这支持从url或assets目录中检索gif。我记录了一切。
如何使用
在xml布局文件中使用它的简单示例:
<[package].GIFView xmlns:gif_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/gif_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"
gif_view:gif_src="asset:gif1" />
代码:
GIF.java:
/**
* Class that represents a gif instance.
*/
public class GIF {
private static final Bitmap.Config DEF_VAL_CONFIG = Bitmap.Config.RGB_565;
private static final int DEF_VAL_DELAY_IN_MILLIS = 33;
// the gif's frames are stored in a movie instance
private Movie movie;
// the canvas of this gif
private Canvas canvas;
// the bitmap of this gif
private Bitmap bitmap;
// the start time of the gif
private long gifStartTime;
// the executor of the gif's thread
private ScheduledExecutorService executor;
// the main runnable of the gif
private Runnable mainRunnable;
// delay in millis between frames
private int delayInMillis;
private OnFrameReadyListener onFrameReadyListener;
private Handler listenerHandler;
private Runnable listenerRunnable;
/**
* Creates Gif instance based on the passed InputStream.
*
* @param in the InputStream
* @throws InputStreamIsNull if in is null
* @throws InputStreamIsEmptyOrUnavailableException if in is empty or unavailable
*/
public GIF(InputStream in) {
this(in, DEF_VAL_CONFIG);
}
/**
* Creates Gif instance based on the passed InputStream and the config.
*
* @param in the InputStream
* @param config the Config
* @throws NullPointerException if config is null
* @throws InputStreamIsNull if in is null
* @throws InputStreamIsEmptyOrUnavailableException if in is empty or unavailable
*/
public GIF(InputStream in, Bitmap.Config config) {
if (in == null)
throw new InputStreamIsNull("the input stream is null");
this.movie = Movie.decodeStream(in);
if (movie == null)
throw new InputStreamIsEmptyOrUnavailableException("the input steam is empty or unavailable");
this.bitmap = Bitmap.createBitmap(movie.width(), movie.height(), config);
// associates the canvas with the bitmap
this.canvas = new Canvas(bitmap);
this.mainRunnable = new Runnable() {
@Override
public void run() {
draw();
invokeListener();
}
};
setDelayInMillis(DEF_VAL_DELAY_IN_MILLIS);
}
/**
* Register a callback to be invoked when the gif changed a frame.
* Invokes methods from a special thread.
*
* @param onFrameReadyListener the listener to attach
*/
public void setOnFrameReadyListener(OnFrameReadyListener onFrameReadyListener) {
setOnFrameReadyListener(onFrameReadyListener, null);
}
/**
* Register a callback to be invoked when the gif changed a frame.
* Invokes methods from the specified handler.
*
* @param onFrameReadyListener the listener to attach
* @param handler the handler
*/
public void setOnFrameReadyListener(OnFrameReadyListener onFrameReadyListener, Handler handler) {
this.onFrameReadyListener = onFrameReadyListener;
listenerHandler = handler;
if (listenerHandler != null)
listenerRunnable = new Runnable() {
@Override
public void run() {
GIF.this.onFrameReadyListener.onFrameReady(bitmap);
}
};
else
listenerRunnable = null;
}
/**
* Sets the delay in millis between every calculation of the next frame to be set.
*
* @param delayInMillis the delay in millis
* @throws IllegalArgumentException if delayInMillis is non-positive
*/
public void setDelayInMillis(int delayInMillis) {
if (delayInMillis <= 0)
throw new IllegalArgumentException("delayInMillis must be positive");
this.delayInMillis = delayInMillis;
}
/**
* Starts the gif.
* If the gif is already running does nothing.
*/
public void startGif() {
if (executor != null)
return;
executor = Executors.newSingleThreadScheduledExecutor();
final int INITIAL_DELAY = 0;
executor.scheduleWithFixedDelay(mainRunnable, INITIAL_DELAY,
delayInMillis, TimeUnit.MILLISECONDS);
}
/**
* Stops the gif.
* If the gif is not running does nothing.
*/
public void stopGif() {
if (executor == null)
return;
executor.shutdown();
// waits until the thread is finished
while (true) {
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
break;
} catch (InterruptedException ignored) {
}
}
executor = null;
}
// calculates the frame and draws it to the bitmap through the canvas
private void draw() {
// if gifStartTime == 0 inits it for the first time
if (gifStartTime == 0)
gifStartTime = SystemClock.uptimeMillis();
long timeElapsed = SystemClock.uptimeMillis() - gifStartTime;
int timeInGif = (int) (timeElapsed % movie.duration());
movie.setTime(timeInGif);
movie.draw(canvas, 0, 0);
}
// invokes the listener
private void invokeListener() {
if (onFrameReadyListener == null)
return;
// if handler was given invokes from it, otherwise invokes from this thread
if (listenerHandler != null)
listenerHandler.post(listenerRunnable);
else
onFrameReadyListener.onFrameReady(bitmap);
}
/**
* Interface definition for a callback to be invoked when the gif changed a frame.
*/
public interface OnFrameReadyListener {
/**
* Called when the gif changed a frame.
* <p>
* Note: If a handler was given with the listener this method
* invokes from the handler, otherwise this method
* invokes from a special thread.
* <p>
* Note: This bitmap is mutable and used by the gif instance
* thus it is not recommended to mutate it.
*
* @param bitmap the new bitmap of the gif
*/
void onFrameReady(Bitmap bitmap);
}
/**
* Definition of a runtime exception class to throw when the inputStream is null.
*/
public static class InputStreamIsNull extends NullPointerException {
/**
* Creates a new instance.
*/
public InputStreamIsNull() {
super();
}
/**
* * Creates a new instance with a message.
*
* @param message the message
*/
public InputStreamIsNull(String message) {
super(message);
}
}
/**
* Definition of a runtime exception class to throw when the inputStream is empty or unavailable.
*/
public static class InputStreamIsEmptyOrUnavailableException extends RuntimeException {
/**
* Creates a new instance.
*/
public InputStreamIsEmptyOrUnavailableException() {
super();
}
/**
* * Creates a new instance with a message.
*
* @param message the message
*/
public InputStreamIsEmptyOrUnavailableException(String message) {
super(message);
}
}
}
GIFView.java:
/**
* A view that can show gifs.
* <p>
* XML Attributes:
* <p>
* gif_src:
* A string that represents the gif's source.
* <p>
* - If you want to get the gif from a url
* concatenate the string "url:" with the full url.
* <p>
* - if you want to get the gif from the assets directory
* concatenate the string "asset:" with the full path of the gif
* within the assets directory. You can exclude the .gif extension.
* <p>
* for example if you have a gif in the path "assets/ex_dir/ex_gif.gif"
* the string should be: "asset:ex_dir/ex_gif"
* <p>
* delay_in_millis:
* A positive integer that represents how many milliseconds
* should pass between every calculation of the next frame to be set.
*/
public class GIFView extends ImageView {
public static final String RESOURCE_PREFIX_URL = "url:";
public static final String RESOURCE_PREFIX_ASSET = "asset:";
private static final int DEF_VAL_DELAY_IN_MILLIS = 33;
// the gif instance
private GIF gif;
// keeps track if the view is in the middle of setting the gif
private boolean settingGif;
private GIF.OnFrameReadyListener gifOnFrameReadyListener;
private OnSettingGifListener onSettingGifListener;
// delay in millis between frames
private int delayInMillis;
/**
* Creates a new instance in the passed context.
*
* @param context the context
*/
public GIFView(Context context) {
super(context);
init(null);
}
/**
* Creates a new instance in the passed context with the specified set of attributes.
*
* @param context the context
* @param attrs the attributes
*/
public GIFView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
// inits the view
private void init(AttributeSet attrs) {
this.gifOnFrameReadyListener = new GIF.OnFrameReadyListener() {
@Override
public void onFrameReady(Bitmap bitmap) {
setImageBitmap(bitmap);
}
};
setDelayInMillis(DEF_VAL_DELAY_IN_MILLIS);
if (attrs != null)
initAttrs(attrs);
}
// inits the view with the specified attributes
private void initAttrs(AttributeSet attrs) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(
attrs, R.styleable.gif_view,
0, 0);
try {
// gets and sets the delay in millis.
int delayInMillis = typedArray.getInt(R.styleable.gif_view_delay_in_millis,
DEF_VAL_DELAY_IN_MILLIS);
if (delayInMillis != DEF_VAL_DELAY_IN_MILLIS)
setDelayInMillis(delayInMillis);
// gets the source of the gif and sets it
String string = typedArray.getString(R.styleable.gif_view_gif_src);
if (string != null)
setGifResource(typedArray.getString(R.styleable.gif_view_gif_src));
} finally {
typedArray.recycle();
}
}
/**
* Register callbacks to be invoked when the view finished setting a gif.
*
* @param onSettingGifListener the listener to attach
*/
public void setOnSettingGifListener(OnSettingGifListener onSettingGifListener) {
this.onSettingGifListener = onSettingGifListener;
}
/**
* Sets the delay in millis between every calculation of the next frame to be set.
*
* @param delayInMillis the delay in millis
* @throws IllegalArgumentException if delayInMillis is non-positive
*/
public void setDelayInMillis(int delayInMillis) {
if (delayInMillis <= 0)
throw new IllegalArgumentException("delayInMillis must be positive");
this.delayInMillis = delayInMillis;
if (gif != null)
gif.setDelayInMillis(delayInMillis);
}
/**
* Returns true if the view is in the process of setting the gif, false otherwise.
*
* @return true if the view is in the process of setting the gif, false otherwise
*/
public boolean isSettingGif() {
return settingGif;
}
/**
* Sets the gif of this view and starts it.
* <p>
* Note that every exception while setting the gif is only sent to the
* OnSettingGifListener instance attached to this view.
* <p>
* If the view has already begun setting another gif, does nothing.
* You can query this state with isSettingGif().
* <p>
* The string passed must be in the following format:
* <p>
* - If you want to get the gif from a url
* concatenate the string "url:" with the full url.
* <p>
* - if you want to get the gif from the assets directory
* concatenate the string "asset:" with the full path of the gif
* within the assets directory. You can exclude the .gif extension.
* <p>
* You can use the Constants:
* <p>
* GIFView.RESOURCE_PREFIX_URL = "url:"
* GIFView.RESOURCE_PREFIX_ASSET = "asset:"
* <p>
* for example if you have a gif in the path "assets/ex_dir/ex_gif.gif"
* invoke the method like this: setGifResource(GIFView.RESOURCE_PREFIX_ASSET + "ex_dir/ex_gif");
*
* @param string the string
* @throws IllegalArgumentException if the string format is invalid
*/
public void setGifResource(String string) {
if (settingGif)
return;
// stops the gif if it is running
if (gif != null)
gif.stopGif();
// defines some finals for readability
final int URL_START_INDEX = RESOURCE_PREFIX_URL.length();
final int ASSET_START_INDEX = RESOURCE_PREFIX_ASSET.length();
final String GIF_EXTENSION = ".gif";
if (string.startsWith(RESOURCE_PREFIX_URL)) {
// notifies setting gif has started
settingGif = true;
// gets the url
String url = string.substring(URL_START_INDEX);
new AsyncSettingOfGif() {
@Override
protected InputStream getGifInputStream(String url) throws Exception {
// gets the input stream from the url
return (InputStream) new URL(url).getContent();
}
}.execute(url);
} else if (string.startsWith(RESOURCE_PREFIX_ASSET)) {
// notifies setting gif has started
settingGif = true;
// gets the asset path
String assetPath = string.substring(ASSET_START_INDEX)
.replaceAll("[\\\\/]", File.separator); // replacing file separators
if (!assetPath.endsWith(GIF_EXTENSION))
assetPath += GIF_EXTENSION;
new AsyncSettingOfGif() {
@Override
protected InputStream getGifInputStream(String assetPath) throws Exception {
// gets the input stream from the assets directory
return GIFView.this.getResources().getAssets().open(assetPath);
}
}.execute(assetPath);
// if string format is invalid
} else {
throw new IllegalArgumentException("string format is invalid");
}
}
/**
* Called when the view finished to set the gif
* or an exception has occurred.
* If there are no exceptions e is null.
* <p>
* Note that the gif can be initialized properly
* and one or more exceptions can be caught in the way.
*
* @param e the Exception
*/
protected void onFinishSettingGif(Exception e) {
// notifies setting the gif has finished
settingGif = false;
if (gif != null)
onSuccess();
else
onFailure(e);
}
// on finish setting the gif
private void onSuccess() {
gif.setOnFrameReadyListener(gifOnFrameReadyListener, getHandler());
gif.setDelayInMillis(delayInMillis);
startGif();
if (onSettingGifListener != null)
onSettingGifListener.onSuccess(this);
}
// when an exception has occurred while trying to set the gif
private void onFailure(Exception e) {
if (onSettingGifListener != null)
onSettingGifListener.onFailure(this, e);
}
/**
* Starts the gif.
* If the gif is already running does nothing.
*
* @throws IllegalStateException if the gif has not been initialized yet
*/
public void startGif() {
if (gif == null || settingGif)
throw new IllegalStateException("the gif has not been initialized yet");
gif.startGif();
}
/**
* Stops the gif.
* If the gif is not running does nothing.
*
* @throws IllegalStateException if the gif has not been initialized yet
*/
public void stopGif() {
if (gif == null || settingGif)
throw new IllegalStateException("the gif has not been initialized yet");
gif.stopGif();
}
/**
* Interface definition for callbacks to be invoked when setting a gif.
*/
public interface OnSettingGifListener {
/**
* Called when a gif has successfully set.
*
* @param view the GIFView
*/
void onSuccess(GIFView view);
/**
* Called when a gif cannot be set.
*
* @param view the GIFView
* @param e the Exception
*/
void onFailure(GIFView view, Exception e);
}
/**
* Definition of an Exception class to throw when the view cannot initialize the gif.
*/
public static class CannotInitGifException extends Exception {
/**
* Creates a new instance.
*/
public CannotInitGifException() {
super();
}
/**
* * Creates a new instance with a message.
*
* @param message the message
*/
public CannotInitGifException(String message) {
super(message);
}
}
/**
* A sub-class of AsyncTask to easily perform an async task of setting a gif.
* <p>
* The default implementation of AsyncSettingOfGif.doInBackground() is to try and init the gif
* from the input stream returned from AsyncSettingOfGif.getGifInputStream() and notify
* GIFView.onFinishSettingGif() sending to it the exception, if occurred, or null.
* <p>
* Implementations of this class should override AsyncSettingOfGif.getGifInputStream()
* to return the right input stream for the gif based on the string argument.
* The string argument can be, for example, a url to retrieve the input stream from.
*/
protected abstract class AsyncSettingOfGif extends AsyncTask<String, Void, Exception> {
@Override
protected Exception doInBackground(String... string) {
CannotInitGifException exceptionToSend = null;
try (InputStream in = getGifInputStream(string[0])) {
// tries to init the gif
gif = new GIF(in);
} catch (Exception e) {
// prepares the message of the exception
String message = e.getMessage();
if (e instanceof FileNotFoundException)
message = "file not found: " + message;
// prepares the exception to send back
exceptionToSend = new CannotInitGifException(message);
}
return exceptionToSend;
}
/**
* Override this method to return the right input stream for the gif based on the string argument.
* The string argument can be, for example, a url to retrieve the input stream from.
*
* @param string the string
* @return an InputStream of a gif
* @throws Exception if an exception has occurred
*/
protected abstract InputStream getGifInputStream(String string) throws Exception;
@Override
protected void onPostExecute(Exception e) {
onFinishSettingGif(e);
}
}
}
RES /值/ attrs.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="gif_view">
<attr name="gif_src" format="string" />
<attr name="delay_in_millis" format="integer" />
</declare-styleable>
</resources>
答案 9 :(得分:0)
你可以添加一个webview并在其中显示一个gif图像,如:
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Rotating_earth_(large).gif/200px-Rotating_earth_(large).gif");
这将在您的应用中显示gif图片。
希望它有所帮助!祝你好运!
答案 10 :(得分:0)
我尝试了很多库来使用gif动画。 但是每个图书馆都是落后和崩溃的。 但是现在,经过一两天的研究,我有了一个使用动画gif的想法,并且表现非常好,没有滞后,没有压榨。
解决方案是使用Glide
按照下面的步骤。
在xml文件中。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#62b849"
tools:context=".MainActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/splace_image_view"
android:layout_centerInParent="true"/>
</RelativeLayout>
以及您的java
文件中
ImageView imageView = findViewById(R.id.splace_image_view);
Glide
.with(this)
.load(R.drawable.football)
.into(imageView);