在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悬浮框与软键盘冲突的问题

Android弹窗探究之PopupWindow的使用

关于laui 弹窗使用弹窗中jsp点击按钮不能用小问题

PopupWindow的简单使用(结合RecyclerView)

弹窗中修改select默认值遇到的问题

Android基础控件——PopupWindow模仿ios底部弹窗