天天看点

android glide加载webp动画设置播放动画次数和监听动画播放完成

需求

产品经理说:需要使用一系列的动画,我说没问题啊,用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);
           

彻底解决!