Resize image to full width and variable height with Picasso
I have a listView with an adapter that contains ImageView
of variable size (width and height). I need resize the pictures load with Picasso to the max width of layout and a variable height given by the aspect ratio of the picture.
I have checked this question: Resize image to full width and fixed height with Picasso
The fit()
works but I haven't found nothing to keep the aspect ratio of the picture.
This code partially works if I fixed the height in the layout of the adapter:
Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.fit().centerInside()
.into(holder.message_picture);
But it generates blank spaces between the pictures of the listView because the pictures may be that not have that height.
Thanks in advance.
Solution 1:
As of Picasso 2.4.0, this operation is now directly supported. Simply add a .resize()
request with one of the dimensions as 0
. For example, to have a variable width, your call would become:
Picasso.with(this.context)
.load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.resize(0, holder.message_picture.getHeight()),
.into(holder.message_picture);
Note that this call uses .getHeight()
and therefore assumes the message_picture
has already been measured. If that isn't the case, such as when you have inflated a new view in a ListAdapter
, you can delay this call until after measurement by adding an OnGlobalLayoutListener
to the view:
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);
}
});
Solution 2:
I came across the same issue and it took me a while to track down a solution but I finally came across something that works for me.
Firstly I changed the Picasso call to
Picasso.with(this.context).load(message_pic_url)
.placeholder(R.drawable.profile_wall_picture)
.into(holder.message_picture);
Removing the fit
and the centerInside
. Next you need to add the following lines to the ImageView in your XML
android:scaleType="fitStart"
android:adjustViewBounds="true"
Hopefully it will work for you as well.
Solution 3:
Finally I solved it doing a transformation of Picasso, here is the snippet:
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);
}
});
This line is for customize with your desired width:
int targetWidth = holder.message_picture.getWidth();
Additionally this snipped include Callback for loading hide and error drawable built-in Picasso.
If you need more information to debug any error, you MUST implement a custom listener (Picasso builder) beacuse the onError
Callback
information is "null". You only know that there is an error for UI behavior.
I hope this helps someone to save many hours.