在PopupWindow弹窗中使用Glide播放GIF完毕后关闭弹窗并跳转Activity
Posted LQS_Android
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在PopupWindow弹窗中使用Glide播放GIF完毕后关闭弹窗并跳转Activity相关的知识,希望对你有一定的参考价值。
最近开发中遇到一个需求:收到特定消息自动调用弹窗播放一个Gif图片,GIF播放一次,播放完毕后,自动跳转到指定的Activity页面。
据说在Glide4.0中,没法再直接获取GifDecoder
对象了,不再支持通过GifDrawable对象调用getDecoder()方法:
drawable.getDecoder()
所以看到这样的统计GIF播放时长再延迟操作的做法是不可行的了,如下:
一般在Glide3.7的时候是这样解决的:
Glide.with(this)
.load("xxxurl")
.listener(new RequestListener<Integer, GlideDrawable>() {
@Override
public boolean onException(Exception arg0, Integer arg1,
Target<GlideDrawable> arg2, boolean arg3) {
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource,
Integer model, Target<GlideDrawable> 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));
除非你通过反射机制去调用,像下面这样,但是会太繁琐:
我这里是采用反射的方法获取到GifDecoder变量的:
public static void loadOneTimeGif(Context context, Object model, final ImageView imageView, final GifListener gifListener) {
Glide.with(context).asGif().load(model).listener(new RequestListener<GifDrawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> 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);
}
/**
* Gif播放完毕回调
*/
public interface GifListener {
void gifPlayComplete();
}
中间的反射代码太费眼,对吧!
看了一些帖子之后,发现两个回调方法是可以返回GIF播放开始时和结束时的状态:
该方式应该只适用于Glide4.9以上版本。代码如下:(我们项目中用的是Glide4.11的)
/**
* 加载开门Gif动图(只播放一次)
* @param view
*/
private var gifDrawable : GifDrawable ?= null //gif动画
private fun loadGif(view: ImageView) {
GlideApp.with(this)
.asGif()
.load(R.mipmap.gold_anim)
.addListener(object :RequestListener<GifDrawable>{
override fun onLoadFailed(e: GlideException?, model: Any?, target: com.bumptech.glide.request.target.Target<GifDrawable>?, isFirstResource: Boolean): Boolean {
e?.printStackTrace()
return true
}
override fun onResourceReady(resource: GifDrawable,model: Any?, target: Target<GifDrawable>?, dataSource:DataSource?, isFirstResource: Boolean): Boolean {
//这个是GifDrawable对象:gifDrawable
gifDrawable = resource
//设置GIF播放次数,这里设置播放1次
gifDrawable?.setLoopCount(1)
gifDrawable?.registerAnimationCallback(object :Animatable2Compat.AnimationCallback() {
override fun onAnimationStart(drawable: Drawable?) {
super.onAnimationStart(drawable)
//添加动画开始时,你需要添加的操作
}
override fun onAnimationEnd(drawable: Drawable?) {
super.onAnimationEnd(drawable)
gifDrawable?.unregisterAnimationCallback(this)
//添加动画播放结束时,你需要的处理
//①如果是在弹窗中播放GIF,此处可以关闭弹窗
//②跳转Activity等操作
}
})
gifDrawable?.start()
return false
}
}).into(view)
}
上面是Kotlin的写法,Java的如下:
GlideUtils.load(mContext,R.drawable.lihegif,giftsGifImg,new RequestListener(){
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Object resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
GifDrawable mDrawable = (GifDrawable) resource;
mDrawable.setLoopCount(1);
mDrawable.registerAnimationCallback(new Animatable2Compat.AnimationCallback() {
@Override
public void onAnimationStart(Drawable drawable) {
super.onAnimationStart(drawable);
}
@Override
public void onAnimationEnd(Drawable drawable) {
super.onAnimationEnd(drawable);
//GIF播放结束后的操作
//关闭弹窗
PopupWindow.this.dismiss();
//或者跳转Activity
if(mDrawable!=null){
mDrawable.unregisterAnimationCallback(this);
}
}
});
return false;
}
});
上面是封装后的GlideUtils,但不影响new RequestListener(){}内部GIF回调方法的使用。
岁月无痕,愿每一篇文章都能铭记此刻努力的你!加油!
以上是关于在PopupWindow弹窗中使用Glide播放GIF完毕后关闭弹窗并跳转Activity的主要内容,如果未能解决你的问题,请参考以下文章
android中使用popupWindow悬浮框与软键盘冲突的问题