Glide: Resize custom ImageView according to downloaded image aspect ratio when it is downloaded

Created on 22 Dec 2015  路  13Comments  路  Source: bumptech/glide

I am loading image into ImageView with fixed height of 200dp and width is set to "wrap_content".

This used to work fine, but then I made my layout a bit more complicated and it stopped working. I'd like to resize ImageView's width programatically just before the image is loaded into it, so that it looks as good as possible.

How can this be done?

question

Most helpful comment

I tried and got this result:
image

Margins are just for fun to make it look nice(r), but not included in below xml. Text has yellow background and image has orange (last 3 are not transparent, but you can see what their bounds are).

Glide
    .with(context)
    .load(getItem(position))
    .into(imageView);
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:orientation="horizontal"
    >
    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="#ff8800"
        />
    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:background="#ffff00"
        />
</LinearLayout>

This confirms that wrap_content works as expected as long as the other dimension is well-defined (match_parent or fixed dp), but it has a problem with recycling views: if I have much more items and scroll back and forth they tend to become more and more square images as shown in @Tanyangfan's last 3 images. The root cause is that once the view is laid out it's size is set from the wrapped image and the next image is loaded to fit that size.

Glide checks if the current getWidth() is a valid size and uses the value if it is. Since the ImageView has been laid out properly with the previous image the recycled values will always be valid.

One way to work around this is to put this line right before the Glide load line:

imageView.layout(0, 0, 0, 0);

This will invalidate the width as it becomes 0 and Glide will not use that dimension.

Another (possibly worse) way to handle this is to separate the "model" from the "view", that is have the display be wrap_content, but tell Glide what size we want:

    .override(Target.SIZE_ORIGINAL, convertView.getLayoutParams().height) // == LinearLayout's fixed 50dp from xml

the problem with this solution is that we're working around the View system, for example the padding/margin is not taken into account.

Weirdly this is what I was asking for in #135... and it works.

All 13 comments

The best is to have match_parent on the ImageView, wrapping is not supported by Glide, it falls back to screen-sized images which is a waste of power and memory. Can you please post your xml surrounding the ImageView and maybe a screenshot of what are you looking to happen? Then I could suggest a way to make Glide happy without dynamic sizing, which is error-prone in general.

It looks like I have the same problem. I use glide in a listView, and the ImageView is 50dp height, wrap_content width. I need to load two kinds size pic, one is 50x50 and the other one is wrap_contentx50. Glide working well at first, but when I drag the listView, which cause the "wrap_content" one hide and appear, the "wrap_content" disppear as 50x50.

Sorry for my poor English. Hope I describe it clear.

Can you please share your XML and a screenshot? (You can blur everything out, I just want to see the structure.)

5azlpet rta 3bln pcm dk
This is the screenshot. The orange color is the background of ImageView, I set it to confirm the ImageView's size. In this pic, the second one is I want, and the first one is witch be resized to 50x50 such as the rest pic.

I will post some screenshots and XML code tomorrow as soon as I have time. Thanks!

I tried and got this result:
image

Margins are just for fun to make it look nice(r), but not included in below xml. Text has yellow background and image has orange (last 3 are not transparent, but you can see what their bounds are).

Glide
    .with(context)
    .load(getItem(position))
    .into(imageView);
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:orientation="horizontal"
    >
    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="#ff8800"
        />
    <TextView
        android:id="@+id/text"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:background="#ffff00"
        />
</LinearLayout>

This confirms that wrap_content works as expected as long as the other dimension is well-defined (match_parent or fixed dp), but it has a problem with recycling views: if I have much more items and scroll back and forth they tend to become more and more square images as shown in @Tanyangfan's last 3 images. The root cause is that once the view is laid out it's size is set from the wrapped image and the next image is loaded to fit that size.

Glide checks if the current getWidth() is a valid size and uses the value if it is. Since the ImageView has been laid out properly with the previous image the recycled values will always be valid.

One way to work around this is to put this line right before the Glide load line:

imageView.layout(0, 0, 0, 0);

This will invalidate the width as it becomes 0 and Glide will not use that dimension.

Another (possibly worse) way to handle this is to separate the "model" from the "view", that is have the display be wrap_content, but tell Glide what size we want:

    .override(Target.SIZE_ORIGINAL, convertView.getLayoutParams().height) // == LinearLayout's fixed 50dp from xml

the problem with this solution is that we're working around the View system, for example the padding/margin is not taken into account.

Weirdly this is what I was asking for in #135... and it works.

Here's my XML layout:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingBottom="10dp"
    android:paddingLeft="5dp"
    android:paddingRight="5dp"
    android:paddingTop="10dp">

    <TextView
        android:id="@+id/timestampTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="8dp"
        android:textSize="12sp"
        android:visibility="gone"
        tools:text="Today, 18:04"/>

    <RelativeLayout
        android:id="@+id/rootLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <TextView
            android:id="@id/nameTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="2.5dp"
            android:layout_marginLeft="8dp"
            android:layout_marginStart="8dp"
            android:layout_toEndOf="@id/item_stream_chat_avatar"
            android:layout_toRightOf="@id/item_stream_chat_avatar"
            android:textSize="10sp"
            tools:text="Name" />

        <RelativeLayout
            android:id="@+id/item_stream_chat_text"
            android:layout_width="wrap_content"
            android:layout_height="200dp"
            android:layout_below="@id/nameTextView"
            android:layout_marginEnd="17.5dp"
            android:layout_marginRight="17.5dp"
            android:layout_toEndOf="@id/item_stream_chat_avatar"
            android:layout_toRightOf="@+id/item_stream_chat_avatar">

            <ImageView
                android:id="@+id/fileImageView"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:adjustViewBounds="true"
                android:background="#d8d8d8"
                android:scaleType="centerInside"/>

            <TextView
                android:id="@+id/fileTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@id/fileImageView"
                android:layout_alignParentBottom="true"
                android:layout_alignRight="@id/fileImageView"
                android:background="#80000000"
                android:ellipsize="end"
                android:lines="1"
                android:paddingBottom="10dp"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:paddingTop="5dp"
                android:textColor="@color/fourth_white"
                tools:text="picture.jpg" />

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignBottom="@id/fileImageView"
                android:layout_alignLeft="@id/fileImageView"
                android:layout_alignRight="@id/fileImageView"
                android:layout_alignTop="@id/fileImageView"
                android:background="@drawable/chat_bubble_image_other"/>

            <com.mikhaellopez.circularprogressbar.CircularProgressBar
                android:id="@+id/circularProgressBar"
                android:layout_width="56dp"
                android:layout_height="56dp"
                android:layout_centerInParent="true"
                android:visibility="gone"
                app:background_progressbar_color="#77ff0000"
                app:background_progressbar_width="3dp"
                app:progressbar_color="#ff0000"
                app:progressbar_width="3dp" />

        </RelativeLayout>

        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/item_stream_chat_avatar"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_alignBottom="@id/item_stream_chat_text"
            android:layout_marginRight="5dp"/>

    </RelativeLayout>
</LinearLayout>

I am using Glide to download images into ImageView with id "fileImageView". As you can see, it has it's height set to "match_parent" which is exactly 200dp. I never want this ImageView to have any other height than 200dp. However, I want width to be completely flexible, hence the "wrap_content".

So when I'm loading an Image to this ImageView, I want the image to take the biggest possible height 200dp (if possible) and then set the width accordingly. If original image's height is under 200dp, then that's understandable that it won't take all the space. Although it would be berfect if I could handle even that.

My code currently works for most use cases:
http://puu.sh/mb6WR/3e3598c116.png
It just starts acting weird when I want to insert a small placeholder or a very small image in general. In those cases, I want to create a fallback which will set the width to 200dp as well and center the image without stretching it. Or something like that.

@matejhacin sorry, this was lost in my queue. Do you still need help?
It sounds like you want #591 (centerInside()) which is not available in v3, but based on #727 you can easily backport and create a transformation for it. Then in the code .transform(new CenterInside(context)) and .into(new GlideDrawableImageViewTarget() {...}) with an overridden onResourceReady to set the width to 200dp when the width is smaller than that. Or for the last part alternatively look into android:minWidth="200dp" which only works if adjustViewBounds is false.

I'm going to close this as it seems that everyone here is happy.
Feel free to argue, and open a new issue if you need more help.

This doesn't work with gifs.

Hi,

I have similar requirement, where height of imageview is fix while width need to be varry based on downloaded image aspect ratio.
i am using glide for this but not able to fix width of image. any insight will help
Glide.with(getContext())
.load(getLogo())
.error(R.drawable.error)
.into(logo);

This is style i am using for imageview

<style name="logo">
    <item name="android:gravity">left</item>
    <item name="android:layout_marginLeft">30dp</item>
    <item name="android:layout_marginTop">26dp</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">12dp</item>
</style>

In my recycler view i have one imageview, image view with match_parent, wrap_content.
When image gets downloaded and load into view, view change its size which looks very weird, when i fixed height of image view, then vertical image gets shrink, how to manage it properly, please help me.

removed DrawableTransitionOptions().crossFade() working fine

Glide.with(mContext).load(item.getImage()).apply(new RequestOptions().placeholder(R.drawable.image_loading)).into((ImageView) helper.getView(R.id.media_image));

Was this page helpful?
0 / 5 - 0 ratings