需求
産品經理說:需要使用一系列的動畫,我說沒問題啊,用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);
徹底解決!