需求
产品经理说:需要使用一系列的动画,我说没问题啊,用gif图不就好了吗?结果,设计师给了我一系列的webp动图。我能怎么办?
先是百度了一番,找到了一个播放webp动画的glide库,库地址是GlideWebpDecoder。
心想,这不就很快搞定了吗?美滋滋!
一阵操作猛如虎…
引用
def GLIDE_VERSION = "4.9.0"
// webpdecoder
implementation "com.zlc.glide:webpdecoder:1.4.${GLIDE_VERSION}"
// glide 4.6.1~4.9.0 (exclude broken version 4.6.0, 4.7.0)
implementation "com.github.bumptech.glide:glide:${GLIDE_VERSION}"
annotationProcessor "com.github.bumptech.glide:compiler:${GLIDE_VERSION}"
真正加载webp动态图
Transformation<Bitmap> circleCrop = new CircleCrop();
WebpDrawableTransformation webpDrawableTransformation = new WebpDrawableTransformation(circleCrop);
Glide.with(this).load(R.mipmap.creative).optionalTransform(circleCrop).optionalTransform(WebpDrawable.class, webpDrawableTransformation).into(imageView);
简直是完美解决呀…
稍微等等,我发现
问题
加载倒是能加载出来,但是不能设置加载次数和监听播放完成。
然后又是百度一番,无果。
最后搜索glide监听gif图片完成的方法,找到了一个链接,如下
原文出处,根据大佬的方法,通过反射拿到每一张图片需要花费的时间,然后发送一个delay事件,就这么简单。
代码
Transformation<Bitmap> circleCrop = new CircleCrop();
WebpDrawableTransformation webpDrawableTransformation = new WebpDrawableTransformation(circleCrop);
Glide.with(this).load(R.mipmap.creative).addListener(new RequestListener<Drawable>() {
@Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
}).optionalTransform(circleCrop).optionalTransform(WebpDrawable.class, webpDrawableTransformation).into(imageView);
先给加载图片添加一个监听webp图是否准备好了.
然后在监听的方法中,加上两个方法,第一个是设置播放次数
private void setLoopCount(WebpDrawable resource,int count) {
WebpDrawable webpDrawable = resource;
webpDrawable.setLoopCount(count);
}
第二个是通过反射拿到webp动图播放的时间
private int getWebpPlayTime(Drawable resource) {
WebpDrawable webpDrawable = (WebpDrawable) resource;
try {
Field gifStateField = WebpDrawable.class.getDeclaredField("state");
gifStateField.setAccessible(true);
Class gifStateClass = Class.forName("com.bumptech.glide.integration.webp.decoder.WebpDrawable$WebpState");
Field gifFrameLoaderField = gifStateClass.getDeclaredField("frameLoader");
gifFrameLoaderField.setAccessible(true);
Class gifFrameLoaderClass = Class.forName("com.bumptech.glide.integration.webp.decoder.WebpFrameLoader");
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);
// 设置只播放一次
// 获得总帧数
int count = webpDrawable.getFrameCount();
int delay = 0;
for (int i = 0; i < count; i++) {
// 计算每一帧所需要的时间进行累加
delay += (int) getDelayMethod.invoke(gifDecoder, i);
}
return 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 0;
}
然后我们就可以彻底的实现产品经理和设计师的需求了。
等等 ,我好像又发现了一个问题,就是第一次播放完成之后,我会移除当前imageview,但是第二次再播放的时候,发现动画不动了。尼玛,
代码之路处处是坑,通过打印监听,发现第二次之后都是使用的内存缓存。
于是去掉内存缓存就好了。
代码如下:
Transformation<Bitmap> circleCrop = new CircleCrop();
WebpDrawableTransformation webpDrawableTransformation = new WebpDrawableTransformation(circleCrop);
Glide.with(this).load(R.mipmap.creative).addListener(new RequestListener<Drawable>() {
@Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
setLoopCount((WebpDrawable) resource,1);
int delay = getWebpPlayTime(resource);
return false;
}
}).optionalTransform(circleCrop).optionalTransform(WebpDrawable.class, webpDrawableTransformation).skipMemoryCache(true).into(imageView);
彻底解决!