天天看点

html只播放一次播放gif,Glide4.0只播放一次Gif以及监听播放完成的实现方法

前言

这篇blog主要记录一下最近刚好遇见的问题,要实现一个gif只播放一次并且要在gif播放完之后回调一下的需求,项目目前用的Glide是4.0版本,这个问题如果在Glide3.7上那么很好解决,网上有一大把的代码示例,但是在Glide4.0的版本上,怎么搜都搜不到类似的,只好自己想方法解决了,好了废话不多说。

解决方法

一般在Glide3.7的时候是这样解决的,

Glide.with(this)

.load("xxxurl")

.listener(new RequestListener() {

@Override

public boolean onException(Exception arg0, Integer arg1,

Target arg2, boolean arg3) {

return false;

}

@Override

public boolean onResourceReady(GlideDrawable resource,

Integer model, Target target,

boolean isFromMemoryCache, boolean isFirstResource) {

// 计算动画时长

GifDrawable drawable = (GifDrawable) resource;

GifDecoder decoder = drawable.getDecoder();

for (int i = 0; i < drawable.getFrameCount(); i++) {

duration += decoder.getDelay(i);

}

//发送延时消息,通知动画结束

handler.sendEmptyMessageDelayed(MESSAGE_SUCCESS,

duration);

return false;

}

}) //仅仅加载一次gif动画

.into(new GlideDrawableImageViewTarget(imageview, 1));

但是在Glide4.0中,没法再直接获取GifDecoder对象了,原因是因为GlideDrawable不再提供这个方法了。

我这里是采用反射的方法获取到GifDecoder变量的,具体代码如下:

public static void loadOneTimeGif(Context context, Object model, final ImageView imageView, final GifListener gifListener) {

Glide.with(context).asGif().load(model).listener(new RequestListener() {

@Override

public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {

return false;

}

@Override

public boolean onResourceReady(GifDrawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {

try {

Field gifStateField = GifDrawable.class.getDeclaredField("state");

gifStateField.setAccessible(true);

Class gifStateClass = Class.forName("com.bumptech.glide.load.resource.gif.GifDrawable$GifState");

Field gifFrameLoaderField = gifStateClass.getDeclaredField("frameLoader");

gifFrameLoaderField.setAccessible(true);

Class gifFrameLoaderClass = Class.forName("com.bumptech.glide.load.resource.gif.GifFrameLoader");

Field gifDecoderField = gifFrameLoaderClass.getDeclaredField("gifDecoder");

gifDecoderField.setAccessible(true);

Class gifDecoderClass = Class.forName("com.bumptech.glide.gifdecoder.GifDecoder");

Object gifDecoder = gifDecoderField.get(gifFrameLoaderField.get(gifStateField.get(resource)));

Method getDelayMethod = gifDecoderClass.getDeclaredMethod("getDelay", int.class);

getDelayMethod.setAccessible(true);

//设置只播放一次

resource.setLoopCount(1);

//获得总帧数

int count = resource.getFrameCount();

int delay = 0;

for (int i = 0; i < count; i++) {

//计算每一帧所需要的时间进行累加

delay += (int) getDelayMethod.invoke(gifDecoder, i);

}

imageView.postDelayed(new Runnable() {

@Override

public void run() {

if (gifListener != null) {

gifListener.gifPlayComplete();

}

}

}, delay);

} catch (NoSuchFieldException e) {

e.printStackTrace();

}catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return false;

}

}).into(imageView);

}

public interface GifListener {

void gifPlayComplete();

}

同时,因为我们采用的是反射,所以别忘了在你的proguard-rules.pro中加上Glide的反混淆规则,

#Glide

-keep class com.bumptech.glide.** {*;}

好了,这样就大功告成啦~

如果觉得对你有所帮助,请点个赞,谢谢。你的鼓励是我最大的动力。

欢迎关注EoniJJ的简书

不定期与你分享关于Android开发的点点滴滴。