Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image size changed after being reloaded #1591

Closed
yuansip opened this issue Nov 17, 2016 · 17 comments
Closed

Image size changed after being reloaded #1591

yuansip opened this issue Nov 17, 2016 · 17 comments
Labels

Comments

@yuansip
Copy link

yuansip commented Nov 17, 2016

3.7.0:

failed on com.android.support:recyclerview-v7:25.0.1:

failed on all devices I have, such as Nexus 5 6.0.1

expected result
snap_20161117_085203
unexpected result
snap_20161117_085222

**:

use Glide to load gif into items of recyclerview, then scroll the recyclerview up and down, the image size is changed after scrolling out of screen then into screen:

Glide load line / GlideModule (if any) / list Adapter code (if any):

        final Uri uri = Uri.parse(urls[i]);
        Glide.with(getContext())
                .load(uri)
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .into(viewHolder.imageView);

Layout XML:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/image"
        android:scaleType="fitCenter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</FrameLayout>

Stack trace / LogCat:

paste stack trace and/or log here
@yuansip
Copy link
Author

yuansip commented Nov 17, 2016

I added some log in onResourceReady and found the size of the GlideDrawable reloaded from cache was changed.

@yuansip
Copy link
Author

yuansip commented Nov 17, 2016

Similar issue:
#1506
If I replace ImageView's height with a fixed value, like 200dp, the issue does not exist anymore.
ImageView with scaleType fitCenter, fitStart, fitEnd has similar issue, other scaleTypes are OK.

@yuansip
Copy link
Author

yuansip commented Nov 17, 2016

I found a workaround:

        Glide.with(getContext())
                .load(urls[i])
                .listener(new RequestListener<Uri, GlideDrawable>() {
                    @Override
                    public boolean onException(Exception e, Uri model, Target<GlideDrawable> target, boolean isFirstResource) {
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(GlideDrawable resource, Uri model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                        GlideDrawableImageViewTarget glideTarget = (GlideDrawableImageViewTarget) target;
                        ImageView iv = glideTarget.getView();
                        int width = iv.getMeasuredWidth();
                        int targetHeight = width * resource.getIntrinsicHeight() / resource.getIntrinsicWidth();
                        if(iv.getLayoutParams().height != targetHeight) {
                            iv.getLayoutParams().height = targetHeight;
                            iv.requestLayout();
                        }
                        return false;
                    }
                })
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .into(viewHolder.imageView);

@TWiStErRob
Copy link
Collaborator

The list items are being reused, and when you scroll down you bind a larger image which makes the ImageView layout taller (wrap_content). When you scroll back up Glide sees that taller size and tries to load an image that has that size. wrap_content only works if the didn't have a layout before, otherwise Glide reads the laid-out width/height and uses that as the target size. I usually recommend a holder.iv.layout(0,0,0,0) to reset the size of the view/target and behave as if the list item was just inflated.

@yuansip
Copy link
Author

yuansip commented Nov 17, 2016

@TWiStErRob, Thanks for your reply. I tried to call viewHolder.imageView.layout(0, 0, 0, 0) in onBindViewHolder(...) as your suggestion, it resolved this issue.

@Ennosukeblade
Copy link

Ennosukeblade commented Apr 27, 2018

I tried this but in the last line it tell me Cannot resolve method 'into(void)'

      Glide.with(c)
                .load(i.getUri())
                .apply(new RequestOptions().fitCenter())
                .apply(new RequestOptions().placeholder(R.drawable.placeholder))
                .into(holder.imgView.layout(0,0,0,0));

@ezhd
Copy link

ezhd commented Jul 1, 2018

@Ennosukeblade I assume you have to call holder.imgView.layout(0,0,0,0); before calling Glide.. because as you said, it returns nothing but null

@jonatlin
Copy link

Adding .override(view.width) worked best for me. Ex:

Glide.with(view.context)
.load(imageUrl)
.override(view.width)
.transition(DrawableTransitionOptions.withCrossFade())
.into(view)

@TWiStErRob
Copy link
Collaborator

@jkailin that only works if you have a fixed width layout, and it'll also shrink taller than wide (portrait shape) images as a side effect. It also should not work on the first bind, interesting if it does for you.

@jonatlin
Copy link

@TWiStErRob Ah that's right. Portrait images have issues. When I use holder.iv.layout(0,0,0,0) some views still don't resize correctly. Is this fix still usable?

@TWiStErRob
Copy link
Collaborator

TWiStErRob commented Jan 12, 2020

@jkailin Based on the many upvotes to my original comment, yes :)
However I don't know if the changes that happened since 3.7 could affect this.
Originally the 0s are meant to trigger this check:
com.bumptech.glide.request.target.ViewTarget.SizeDeterminer#isSizeValid

return size > 0 || size == LayoutParams.WRAP_CONTENT;

I'm not sure if it still exists in a fairly similar for in v4.

@squm
Copy link

squm commented Apr 29, 2020

centering image on the left, as you would with TextView gravity="center_vertical|start" using scaleType="fitStart" and layout_height="wrap_content". And there the images have incorrect smaller size, probably they keep the preloaded resolution?

@franciscobarrios
Copy link

Still happening, in my case I'm using different dimensionRatio (from ConstraintLayout) go show image, files and videos, and to fix the problem the solution was:

fun ImageView.resizeImage(imagePath: String?, placeholder: Int) {
       this.layout(0,0,0,0)  // <------- 
            GlideApp.with(context.applicationContext)
                   .load(imagePath)
                   .apply(options)
                   .fitCenter()
                   .centerCrop()
                   .into(this)
           }

@bobguy1234
Copy link

holder.imgView.layout(0,0,0,0); causes a snapping effect that instantly scrolls all the way to the first item

@james04gr
Copy link

holder.imgView.layout(0,0,0,0); causes a snapping effect that instantly scrolls all the way to the first item

This is because when the view is created it has a height of 0, and when Glide loads the image suddenly the height of an item changes, so it pushes other items down/up (according to orientation scroll)

Any idea how to fix this?

@GerardoRobledo
Copy link

@james04gr if you have a predefined height for the items, you can use that value for the bottom param.
holder.imgView.layout(0,0,0,itemHeight);

@TWiStErRob
Copy link
Collaborator

If you have predefined size (e.g. 123dp), just set <ImageView android:layout_width="wrap_content" android:layout_height="123dp" and then you don't need this .layout() hack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants