web-dev-qa-db-fra.com

Glisse: charge tirable mais ne redimensionne pas l'espace réservé

Existe-t-il un moyen d'utiliser Glide pour attribuer un espace réservé mais conserver cette image à son échelle d'origine? J'ai un ImageView avec une taille variable (en fonction de l'image entrante) que j'ai défini avant d'appeler Glide.with().load().into() et je veux utiliser un espace réservé pour cela mais je ne veux pas que l'espace réservé soit redimensionné à la taille du ImageView, je veux qu'il garde sa taille d'origine.

Jusqu'à présent, je n'ai pas trouvé de moyen de le faire.

20
Fernando

Re: Gregs comment : Je lui ai donné un autre coup (avec près d'un an d'XP supplémentaire) et j'ai trouvé ceci:

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

similaire à mon autre solution et au wrapper d'animation suivant:

...
    .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);
    }
}

Les parties triviales des implémentations sont omises, le constructeur de chaque classe initialise les champs à partir des arguments. Code complet disponible sur GitHub dans TWiStErRob/glide-support .

crossFaded placeholder


Si vous êtes bloqué sur une ancienne version de Glide (avant 3.8.0), le même effet peut être obtenu en:

.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));
    }
})

Notez que les deux solutions nécessitent la même quantité de classes, mais la solution post-3.8.0 a une meilleure séparation des préoccupations et peut être mise en cache dans une variable pour éviter les allocations.

13
TWiStErRob

Il y a un problème Glide connu des espaces réservés déformant les images chargées et vice versa . Cependant, je pense que cela ne vous affecte pas.

Il semble que ce que vous voulez, c'est montrer l'espace réservé dessinable avec scaleType="center" Et vous voulez que l'image chargée soit scaleType="fitCenter". Voici comment vous exprimez cela dans Glide. Ajoutez Android:scaleType="center" Dans le XML et utilisez la ligne de chargement Glide suivante:

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

L'astuce est que l'espace réservé est défini via setImageDrawable() afin que l'ImageView l'affiche comme d'habitude, mais vous dites à Glide d'utiliser explicitement le FitCenter qui s'adaptera bien à l'image chargée dans l'ImageView. disposé la taille via une transformation, puis définissez-le via setImageDrawable(). Comme l'image ajustée est parfaitement ajustée, center dessinera simplement l'image couvrant toute la zone de la vue.

Vous pouvez également utiliser .centerCrop() de la même manière.

Si quelque chose ne va pas, vous pouvez essayer .asBitmap() et .dontAnimate(), ils aident la plupart du temps d'une manière ou d'une autre.

14
TWiStErRob

Je le fais comme mentionné ci-dessous:

L'idée est de définir le type d'échelle comme requis par l'espace réservé initialement et d'attacher l'auditeur pour changer à nouveau le type d'échelle comme requis par l'image téléchargée après le téléchargement de l'image.

//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);

Ma transition drawable (R.drawable.anim_image_placeholder):

(non requis si vous utilisez une image statique)

<?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>
3
Swas_99