Cambiar el tamaño de la imagen a ancho completo y altura variable con Picasso

Tengo un listView con un adaptador que contiene ImageView de tamaño variable (ancho y alto). Necesito redimensionar la carga de imágenes con Picasso al máximo ancho de diseño y una altura variable dada por la relación de aspecto de la imagen.

He verificado esta pregunta: cambiar el tamaño de la imagen a todo el ancho y la altura fija con Picasso

El fit() funciona pero no he encontrado nada para mantener la relación de aspecto de la imagen.

Este código funciona parcialmente si fijé la altura en el diseño del adaptador:

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

Pero genera espacios en blanco entre las imágenes de la lista Vista porque las imágenes pueden ser de una altura que no tiene esa altura.

Gracias por adelantado.

A partir de Picasso 2.4.0, esta operación ahora es directamente compatible . Simplemente agregue una solicitud .resize() con una de las dimensiones como 0 . Por ejemplo, para tener un ancho variable, su llamada se convertiría en:

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

Tenga en cuenta que esta llamada usa .getHeight() y por lo tanto asume que la .getHeight() ya ha sido medida. Si ese no es el caso, como cuando ha inflado una nueva vista en un ListAdapter , puede retrasar esta llamada hasta después de la medición agregando un OnGlobalLayoutListener a la vista:

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

Me encontré con el mismo problema y me tomó un tiempo encontrar una solución, pero finalmente encontré algo que me funciona.

Primero cambié la llamada de Picasso a

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

Eliminando el fit y el centro centerInside . A continuación, debe agregar las siguientes líneas a ImageView en su XML

 android:scaleType="fitStart" android:adjustViewBounds="true" 

Espero que funcione también para usted.

Finalmente lo resolví haciendo una transformación de Picasso, aquí está el fragmento:

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

Esta línea es para personalizar con su ancho deseado:

 int targetWidth = holder.message_picture.getWidth(); 

Además, esta versión cortada incluye la callback para cargar el Picasso incorporado oculto y oculto.

Si necesita más información para depurar cualquier error, DEBE implementar un escucha personalizado (generador de Picasso) porque la información de onError Callback onError es “nula”. Solo sabe que hay un error en el comportamiento de la interfaz de usuario.

Espero que esto ayude a alguien a ahorrar muchas horas.

La respuesta aceptada de mayo es útil para todos, pero si está vinculando Multiple ViewHolder para múltiples Views entonces puede reducir su código creando clases para transformación y pasando ImageView desde 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"; } }; } } 

Llamar desde 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); 

Espero que te ayude.

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

Esto te ayudará con la altura variable de las imágenes para todos los dispositivos

Escribí un asistente sencillo que se encarga de agregar el oyente de diseño completo y llamar a (imageView) cuando se completa el proceso de diseño.

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

}

Así que puedes usarlo fácilmente así por ejemplo en el fragmento en ViewCreated ()

 new PicassoDelegate(customerPhoto, Picasso.with(getActivity()).load(user.getPhotoUrl()).centerCrop()); 
 imageView.post(new Runnable() { @Override public void run() { Picasso.with(context) .resize(0, imageView.getHeight()) .onlyScaleDown() .into(imageView, new ImageCallback(callback, null)); } }); 
 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 + ")"; } 

Más transformaciones: https://github.com/wasabeef/picasso-transformations

extienda ImageView y anule el método de medición como el siguiente.

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

En realidad estaba entrando mientras cargaba la imagen en CustomImageView que tenía una funcionalidad de zoomable

Error fue

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

Lo resolví editando el código proporcionado por la respuesta aceptada. Obtuve el ancho máximo de mi pantalla como si mi ancho de vista de la imagen ya fuera 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"; } }; }