有没有办法强制加载 Glide 的 gif 成为非动画

Is there a way to force gif loaded with Glide to be non-animated

我有一组图像,通过 Glide 加载。

NSFW 使用 glide (wasabeef) 位图变换进行模糊处理,但是有些可以是 gif 动画,在这种情况下第一帧显示为模糊处理,然后动画开始循环(未模糊处理)。

以下是我试过的方法,但没有用:

DrawableTypeRequest<String> builder = Glide.with(mImage.getContext()).load(...);

if (entry.isNsfw()) {
    builder.asBitmap();
}

builder.diskCacheStrategy(DiskCacheStrategy.SOURCE) //it's likely none of this is relevant
    .skipMemoryCache(true)
    .override(props.getWidth(), props.getHeight());

if (entry.isNsfw()) {
    //successfully blurs nsfw images, but still allows unblurred animation
    builder.dontAnimate().bitmapTransform(centreCrop, blur);
} else {
    builder.centerCrop();
}

builder.crossFade(500) //moving crossfade only into the sfw posts has no effect
       .into(mImage);

拦截负载也不起作用:

builder.listener(new RequestListener<String, GlideDrawable>() {
    @Override
    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
        return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        if (entry.isNsfw()) {
            target.onResourceReady(resource, null); //If I add this and return true the image is static, but unblurred
            resource.stop(); //if this is called before target, it has no effect
            return true;
        }
        return false; //returning true without calling the target stops any of the images being set on the view
    }
});

如何在保持模糊变换的同时关闭单个图像的 gif 播放?

I have a set of images, loaded via Glide

根据以上内容,我假设您正在使用 RecyclerView 来显示这些图像,我的回答基于此假设。

尝试使用您自己的自定义 Glide 目标来停止动画,如果 NSFW 喜欢这样的话

public class CustomTarget extends GlideDrawableImageViewTarget {

    private boolean isNSFW;

    public CustomTarget(ImageView view) {
        super(view);
    }

    public void setNSFW(boolean isNSFW){
        this.isNSFW = isNSFW;
    }

    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {

        // this super call loads the image, sets it to the ImageView and starts
        // animating if it is Gif
        super.onResourceReady(resource, animation); 

        if(isNSFW){
            onStop(); // stop playing the animation if NSFW
        }
    }
}

并且在您的 View Holder class 中,创建并保留对此目标的引用,就像您对其他视图所做的那样

public class MyViewHolder extends RecyclerView.ViewHolder {

    ImageView myImageView;
    CustomTarget myCustomTarget;

    public MyViewHolder(View itemView) {
        super(itemView);
        myImageView = (ImageView) itemView.findViewById(R.id.myIv);
        myCustomTarget = new CustomTarget(myImageView);
    }
}

然后在 onBindViewHolder 中执行以下操作

public void onBindViewHolder(MyViewHolder holder, int position) {

    // get the current entry in your image set
    final Entry entry = entries.get(position); 

    // call this before loading the resource
    holder.myCustomTarget.setNSFW(entry.isNSFW()); 

    // No need to specify asGif()
    // Refer 
    Glide.with(context)
            .load(entry.getURL())
            .into(holder.myCustomTarget);

}

我自己还没有测试过这个解决方案。但我希望它能让您了解如何解决这个问题。

最后混合了我在问题中概述的几个步骤,解决了问题。动画 NSFW gif 现在仅显示第一帧,已成功模糊。

DrawableRequestBuilder<String> builder = Glide.with(ctx).load(...);
if (nsfw) {
    builder.bitmapTransform(new BlurTransformation(ctx, 8, 16), new CentreCrop(...));
} else {
    builder.centerCrop();
}
builder.listener(new RequestListener<String, GlideDrawable>() {
    ... //onException method
    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        boolean handled = false;
        if (nsfw && resource.isAnimated()) {
            target.onResourceReady(new GlideBitmapDrawable(null, ((GifDrawable) resource).getFirstFrame()), null);
            handled = true; //glide now won't set the resource on the target itself
        }
        return handled;
    }
});
builder.crossFade(500).into(mImageView);