25

有没有办法使用 Glide 分配一个占位符但保持这个图像的原始比例?我有一个ImageView可变大小(取决于传入的图像),我在调用之前设置Glide.with().load().into()了它,我想为它使用一个占位符,但不希望将占位符调整为 的大小ImageView,我希望它保持其原始尺寸。

到目前为止,我找不到这样做的方法。

4

3 回答 3

19

有一个已知的 Glide 问题,即占位符会扭曲加载的图像,反之亦然。但是,我认为您不受此影响。

听起来您想要显示可绘制的占位符,scaleType="center"并且您希望加载的图像是scaleType="fitCenter". 以下是您在 Glide 中的表达方式。添加android:scaleType="center"XML 并使用以下 Glide 加载线:

Glide.with(...).load(...).placeholder(R.drawable....).fitCenter().into(imageView);

诀窍是占位符是通过设置的,setImageDrawable()因此 ImageView 将像往常一样显示它,但是您告诉 Glide 使用FitCenter显式,它将通过 Transformation 很好地适合加载的图像在 ImageView 的布局大小内,然后通过setImageDrawable(). 由于拟合的图像是完美的拟合,center因此只会绘制覆盖整个视图区域的图像。

你也可以用.centerCrop()同样的方法。

如果出现问题,您可以尝试.asBitmap().dontAnimate()它们在大多数情况下都会以一种或另一种方式提供帮助。

于 2015-10-01T11:08:45.050 回答
13

回复:Gregs 评论:我又给了它一次机会(几乎一年的额外 XP)并想出了这个:

<ImageView android:scaleType="center" ... />

类似于我的其他解决方案和以下动画包装器:

...
    .fitCenter()
    .animate(new PaddingAnimationFactory<>(new DrawableCrossFadeFactory<GlideDrawable>(2000)))
    .into(imageView)
;

class PaddingAnimationFactory<T extends Drawable> implements GlideAnimationFactory<T> {
    private final DrawableCrossFadeFactory<T> realFactory;
    @Override public GlideAnimation<T> build(boolean isFromMemoryCache, boolean isFirstResource) {
        return new PaddingAnimation<>(realFactory.build(isFromMemoryCache, isFirstResource));
    }
}

class PaddingAnimation<T extends Drawable> implements GlideAnimation<T> {
    private final GlideAnimation<? super T> realAnimation;
    @Override public boolean animate(T current, final ViewAdapter adapter) {
        int width = current.getIntrinsicWidth();
        int height = current.getIntrinsicHeight();
        return realAnimation.animate(current, new PaddingViewAdapter(adapter, width, height));
    }
}

class PaddingViewAdapter implements ViewAdapter {
    @Override public Drawable getCurrentDrawable() {
        Drawable drawable = realAdapter.getCurrentDrawable();
        if (drawable != null) {
            int padX = Math.max(0, targetWidth - drawable.getIntrinsicWidth()) / 2;
            int padY = Math.max(0, targetHeight - drawable.getIntrinsicHeight()) / 2;
            if (padX != 0 || padY != 0) {
                drawable = new InsetDrawable(drawable, padX, padY, padX, padY);
            }
        }
        return drawable;
    }
    @Override public void setDrawable(Drawable drawable) {
        if (VERSION.SDK_INT >= VERSION_CODES.M && drawable instanceof TransitionDrawable) {
            // For some reason padding is taken into account differently on M than before in LayerDrawable
            // PaddingMode was introduced in 21 and gravity in 23, I think NO_GRAVITY default may play
            // a role in this, but didn't have time to dig deeper than this.
            ((TransitionDrawable)drawable).setPaddingMode(TransitionDrawable.PADDING_MODE_STACK);
        }
        realAdapter.setDrawable(drawable);
    }
}

省略了实现的琐碎部分,每个类的构造函数都从参数初始化字段。完整代码可在GitHub 上的 TWiStErRob/glide-support 中找到

交叉淡化占位符


如果您卡在旧版本的 Glide(3.8.0 之前),可以通过以下方式实现相同的效果:

.fitCenter()
.placeholder(R.drawable.glide_placeholder)
.crossFade(2000)
.into(new GlideDrawableImageViewTarget(imageView) {
    @Override public void onResourceReady(GlideDrawable resource,
            GlideAnimation<? super GlideDrawable> animation) {
        super.onResourceReady(resource, new PaddingAnimation<>(animation));
    }
})

请注意这两种解决方案如何需要相同数量的类,但 3.8.0 后的解决方案具有更好的关注点分离,并且可以缓存在变量中以防止分配。

于 2016-04-29T17:12:11.433 回答
3

我这样做如下所述:

这个想法是最初将比例类型设置为占位符的要求并附加侦听器以在下载图像后再次将比例类型更改为下载图像的要求。

//ivBuilderLogo = Target ImageView
//Set the scale type to as required by your place holder
//ScaleType.CENTER_INSIDE will maintain aspect ration and fit the placeholder inside the image view
holder.ivBuilderLogo.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 

//AnimationDrawable is required when you are using transition drawables
//You can directly send resource id to glide if your placeholder is static
//However if you are using GIFs, it is better to create a transition drawable in xml 
//& use it as shown in this example
AnimationDrawable animationDrawable;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
     animationDrawable=(AnimationDrawable)context.getDrawable(R.drawable.anim_image_placeholder);
else
     animationDrawable=(AnimationDrawable)context.getResources().getDrawable(R.drawable.anim_image_placeholder);
animationDrawable.start();

Glide.with(context).load(logo_url)
                   .placeholder(animationDrawable)
                   .listener(new RequestListener<String, GlideDrawable>() {
                        @Override
                        public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource)
                        {
                           return false;
                        }

                        //This is invoked when your image is downloaded and is ready 
                        //to be loaded to the image view
                        @Override
                        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource)
                        {   
                        //This is used to remove the placeholder image from your ImageView 
                        //and load the downloaded image with desired scale-type(FIT_XY in this case)
                        //Changing the scale type from 'CENTER_INSIDE' to 'FIT_XY' 
                        //will stretch the placeholder for a (very) short duration,
                        //till the downloaded image is loaded
                        //setImageResource(0) removes the placeholder from the image-view 
                        //before setting the scale type to FIT_XY and ensures that the UX 
                        //is not spoiled, even for a (very) short duration
                            holder.ivBuilderLogo.setImageResource(0);
                            holder.ivBuilderLogo.setScaleType(ImageView.ScaleType.FIT_XY);
                            return false;
                        }
                    })
                    .into( holder.ivBuilderLogo);

我的过渡可绘制(R.drawable.anim_image_placeholder):

(如果使用静态图像则不需要)

<?xml version="1.0" encoding="utf-8"?>
<animation-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/loading_frame1" android:duration="100" />
    <!--<item android:drawable="@drawable/loading_frame2" android:duration="100" />-->
    <item android:drawable="@drawable/loading_frame3" android:duration="100" />
    <!--<item android:drawable="@drawable/loading_frame4" android:duration="100" />-->
    <item android:drawable="@drawable/loading_frame5" android:duration="100" />
    <!--<item android:drawable="@drawable/loading_frame6" android:duration="100" />-->
    <item android:drawable="@drawable/loading_frame7" android:duration="100" />
    <!--<item android:drawable="@drawable/loading_frame8" android:duration="100" />-->
    <item android:drawable="@drawable/loading_frame9" android:duration="100" />
    <!--<item android:drawable="@drawable/loading_frame10" android:duration="100" />-->
</animation-list>
于 2017-01-04T08:45:44.927 回答