web-dev-qa-db-fra.com

Redimensionner l'image à pleine largeur et à hauteur variable avec Picasso

J'ai un listView avec un adaptateur qui contient ImageView de taille variable (largeur et hauteur). J'ai besoin de redimensionner les images chargées avec Picasso à la largeur maximale de la mise en page et à une hauteur variable en fonction du format de l'image.

J'ai vérifié cette question: Redimensionner l’image à pleine largeur et à hauteur fixe avec Picasso

fit() fonctionne mais je n'ai rien trouvé qui permette de conserver les proportions de l'image.

Ce code fonctionne partiellement si je fixe la hauteur dans la présentation de l'adaptateur:

Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.fit().centerInside()
.into(holder.message_picture);

Mais il génère des espaces vides entre les images de la liste, car les images peuvent ne pas avoir cette hauteur.

Merci d'avance.

73
wendigo

Finalement je l'ai résolu en transformant Picasso, voici l'extrait:

    Transformation transformation = new Transformation() {

        @Override
        public Bitmap transform(Bitmap source) {
            int targetWidth = holder.message_picture.getWidth();

            double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
            int targetHeight = (int) (targetWidth * aspectRatio);
            Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
            if (result != source) {
                // Same bitmap is returned if sizes are the same
                source.recycle();
            }
            return result;
        }

        @Override
        public String key() {
            return "transformation" + " desiredWidth";
        }
    };

    mMessage_pic_url = message_pic_url;

    Picasso.with(this.context)
        .load(message_pic_url)
        .error(Android.R.drawable.stat_notify_error)
        .transform(transformation)
        .into(holder.message_picture, new Callback() {
            @Override
            public void onSuccess() {
                holder.progressBar_picture.setVisibility(View.GONE);
            }

            @Override
            public void onError() {
                Log.e(LOGTAG, "error");
                holder.progressBar_picture.setVisibility(View.GONE);
            }
    });

Cette ligne est à personnaliser avec la largeur souhaitée:

int targetWidth = holder.message_picture.getWidth();

De plus, cette partie inclut le rappel pour le chargement de Picasso intégré pouvant être masqué et d'erreur.

Si vous avez besoin de plus d'informations pour déboguer une erreur, vous DEVEZ implémenter un écouteur personnalisé (constructeur Picasso) car les informations onErrorCallback sont "null". Vous savez seulement qu'il y a une erreur pour le comportement de l'interface utilisateur.

J'espère que cela aide quelqu'un à économiser beaucoup d'heures.

55
wendigo

Depuis Picasso 2.4.0, cette opération est maintenant directement supportée . Ajoutez simplement une demande .resize() avec l’une des dimensions sous la forme 0. Par exemple, pour avoir une largeur variable, votre appel deviendrait:

Picasso.with(this.context)
       .load(message_pic_url)
       .placeholder(R.drawable.profile_wall_picture)
       .resize(0, holder.message_picture.getHeight()),
       .into(holder.message_picture);

Notez que cet appel utilise .getHeight() et suppose donc que message_picture a déjà été mesuré. Si ce n'est pas le cas, par exemple lorsque vous avez gonflé une nouvelle vue dans une ListAdapter, vous pouvez retarder cet appel jusqu'à la mesure suivante en ajoutant une OnGlobalLayoutListener à la vue:

holder.message_picture.getViewTreeObserver()
      .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            // Wait until layout to call Picasso
            @Override
            public void onGlobalLayout() {
                // Ensure we call this only once
                imageView.getViewTreeObserver()
                         .removeOnGlobalLayoutListener(this);


                Picasso.with(this.context)
                       .load(message_pic_url)
                       .placeholder(R.drawable.profile_wall_picture)
                       .resize(0, holder.message_picture.getHeight())
                       .into(holder.message_picture);
            }
        });
81
George Hilliard

Je suis tombé sur le même problème et il m'a fallu un certain temps pour trouver une solution, mais j'ai finalement trouvé quelque chose qui me convient.

J'ai tout d'abord changé l'appel de Picasso en

Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);

Suppression de fit et de centerInside. Ensuite, vous devez ajouter les lignes suivantes à ImageView dans votre fichier XML

Android:scaleType="fitStart"
Android:adjustViewBounds="true"

J'espère que cela fonctionnera pour vous aussi.

72
drspaceboo

Mai Accepté La réponse est utile à tous, mais si vous liez plusieurs ViewHolder pour plusieurs Views, vous pouvez réduire votre code en créant Class pour Transformation et en passant ImageView à partir de ViewHolder.

/**
 * Created by Pratik Butani
 */
public class ImageTransformation {

    public static Transformation getTransformation(final ImageView imageView) {
        return new Transformation() {

            @Override
            public Bitmap transform(Bitmap source) {
                int targetWidth = imageView.getWidth();

                double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
                int targetHeight = (int) (targetWidth * aspectRatio);
                Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
                if (result != source) {
                    // Same bitmap is returned if sizes are the same
                    source.recycle();
                }
                return result;
            }

            @Override
            public String key() {
                return "transformation" + " desiredWidth";
            }
        };
    }
}

En appelant de ViewHolder:

Picasso.with(context).load(baseUrlForImage)
                     .transform(ImageTransformation.getTransformation(holder.ImageView1))
                     .error(R.drawable.ic_place_holder_circle)
                     .placeholder(R.drawable.ic_place_holder_circle)
                     .into(holder.mMainPhotoImageView1);

J'espère que cela vous aidera.

8
Pratik Butani
    Picasso.with(this).load(url).resize(1800, 1800).centerInside().into(secondImageView)

    <ImageView
        Android:id="@+id/SecondImage"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:layout_alignParentStart="true"
        Android:layout_alignParentLeft="true"
        Android:adjustViewBounds="true"
        Android:layout_margin="10dp"
        Android:visibility="gone"/>

Cela vous aidera avec une hauteur d'image variable pour tous les appareils.

2
Kiran

J'ai écrit une application simple qui prend en charge l'ajout d'un écouteur de présentation complète et l'appel à (imageView) lorsque le processus de présentation est terminé.

public class PicassoDelegate {

private RequestCreator mRequestCreator;

public PicassoDelegate(ImageView target, RequestCreator requestCreator) {
    if (target.getWidth() > 0 && target.getHeight() > 0) {
        complete(target, requestCreator);
    } else {
        mRequestCreator = requestCreator;
        target.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                v.removeOnLayoutChangeListener(this);
                complete((ImageView) v, mRequestCreator);
            }
        });

    }

}

private void complete(ImageView target, RequestCreator requestCreator) {
    if (target.getWidth() > 0 && target.getHeight() > 0) {
        requestCreator.resize(target.getWidth(), target.getHeight());
    }

    requestCreator.into(target);
}

}

Donc, vous pouvez facilement l'utiliser comme ceci par exemple dans onViewCreated () de fragment

new PicassoDelegate(customerPhoto, Picasso.with(getActivity()).load(user.getPhotoUrl()).centerCrop());
0
Dmytro
imageView.post(new Runnable() {
      @Override public void run() {
        Picasso.with(context)
            .resize(0, imageView.getHeight())
            .onlyScaleDown()
            .into(imageView, new ImageCallback(callback, null));
      }
    });
0
Igor Bykov

En fait, je rentrais en chargeant l'image dans CustomImageView qui avait une fonctionnalité zoomable 

Erreur était

Java.lang.RuntimeException: Transformation transformation desiredWidth crashed with exception.

Je l'ai résolu en modifiant le code donné par la réponse acceptée, j'ai obtenu la largeur maximale de mon affichage comme si ma largeur d'image était déjà match_parent.

if (! imgUrl.equals ("")) {

        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int height = displayMetrics.heightPixels;
        int width = displayMetrics.widthPixels;

        Picasso.with(context).load(imgUrl)
                .transform(getTransformation(width, imageView))
                .into(imageView, new Callback() {
                    @Override
                    public void onSuccess() {
                        if (progressBar != null) {
                            progressBar.setVisibility(View.GONE);
                        }
                    }

                    @Override
                    public void onError() {
                        if (progressBar != null) {
                            progressBar.setVisibility(View.GONE);
                        }
                    }
                });
    }

    public static Transformation getTransformation(final int width, final ImageView imageView) {
        return new Transformation() {
            @Override
            public Bitmap transform(Bitmap source) {
                int targetWidth = width;
                double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
                int targetHeight = (int) (targetWidth * aspectRatio);
                Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
                if (result != source) {
                    // Same bitmap is returned if sizes are the same
                    source.recycle();
                }
                return result;
            }

            @Override
            public String key() {
                return "transformation" + " desiredWidth";
            }
        };
    }
0
Vivek Barai
public class CropSquareTransformation implements Transformation {

  private int mWidth;
  private int mHeight;

  @Override public Bitmap transform(Bitmap source) {
    int size = Math.min(source.getWidth(), source.getHeight());

    mWidth = (source.getWidth() - size) / 2;
    mHeight = (source.getHeight() - size) / 2;

    Bitmap bitmap = Bitmap.createBitmap(source, mWidth, mHeight, size, size);
    if (bitmap != source) {
      source.recycle();
    }

    return bitmap;
  }

  @Override public String key() {
    return "CropSquareTransformation(width=" + mWidth + ", height=" + mHeight + ")";
  }

Plus de transformations: https://github.com/wasabeef/picasso-transformations

0
Pablo Cegarra
Picasso.get()
.load(message_pic_url)
.fit()
.centerCrop()
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);

Essayez ce code, a travaillé pour moi.

0
Afinas EM

étendez ImageView puis substituez la méthode onMeasure comme suit.

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        Drawable d = getDrawable();

        if(d!=null && fittingType == FittingTypeEnum.FIT_TO_WIDTH){
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = (int) Math.ceil((float) width * (float) d.getIntrinsicHeight() / (float) d.getIntrinsicWidth());
            setMeasuredDimension(width, height);
        }else{
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
0
Jinichi