Im trying to create a run of the mill regular staggeredgrid of images using a recyclerview. Im using Glide to load the images from urls. For some reason, im getting some strange behavior when scrolling, views move on their own, weird layouts and spaces between views etc. Its hard to explain so heres a screenrecording: http://gfycat.com/BaggyOffensiveAnglerfish
Code im using is pretty basic:
The grid item:
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxHeight="150dp"
/>
Glide code:
Glide.with(mContext).load(entry.getImageUrl()).into(holder.gridImageView);
Layout manager is just a basic StaggeredGridLayoutManager:
mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
Im sure that somebody has came across a similar issue to this given how popular Glide is. Whats going on here? Any ideas?
Im trying to make a regular staggeredgrid, eg: http://prntscr.com/9mo4bm where items all have the same width, but differing heights depending on original imagesize/aspect ratio.
wrap_content is not fully supported by Glide, read this: https://github.com/bumptech/glide/issues/835#issuecomment-167438903 your problem is view reuse: the sizes are getting funky.
@TWiStErRob Ah that seemed to fix it a bit. Switched width to match_parent for the items. There was still some other small spaces being created when the view was recycled, perhaps because i was still using wrap_content for the height. Gonna close this, thanks.
Try the layout(0,0,0,0) trick. It'll have to relayout anyway, because wrap changes height.
If you happen to know the image's dimensions in advance, you can set the appropriate layout constraints with PercentFrameLayout from compile 'com.android.support:percent:23.0.0'.
E.g. For a vertical staggered list manager
The view you'll inflate in RecyclerView.Adapter#onCreateViewHolder
<android.support.percent.PercentFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
app:layout_widthPercent="100%" />
</android.support.percent.PercentFrameLayout>
public void onBindViewHolder(GiphyViewHolder holder, int position) {
PercentFrameLayout.LayoutParams layoutParams = (PercentFrameLayout.LayoutParams) holder.imageView.getLayoutParams();
layoutParams.getPercentLayoutInfo().aspectRatio = (float)srcWidth / (float)srcHeight;
holder.imageView.setLayoutParams(layoutParams);
}
The above solution works fine but you need
compile 'com.android.support:percent:23.1.1'
and also make sure that srcWidth and srcHeight are floats: it was rounding off my integers which got me very confused for a second ;)
@bryanstern I tried this too in https://github.com/TWiStErRob/glide-support/commit/a1572179430e837d8410cc9f915d7c4737e584dd and PercentLayoutHelper.PercentLayoutInfo#fillLayoutParams tricked me:
We assume that width/height set to 0 means that value was unset. This might not necessarily be true, as the user might explicitly set it to 0. However, we use this information only for the aspect ratio. If the user set the aspect ratio attribute, it means they accept or soon discover that it will be disregarded.
Without adding a height = 0, the percent didn't work as the aspect ratio was not taken into account:
layoutParams.getPercentLayoutInfo().aspectRatio = newAspect;
layoutParams.height = 0;
image.setLayoutParams(layoutParams);
how come this didn't come up for you?
@TWiStErRob, what is layoutParams.height on the first view bind? What happens if you don't include
android:layout_width="match_parent"
android:layout_height="wrap_content"
in your ImageView? I don't have those there as I believe they will conflict with calculation of layout params.
The same happens, that's just for compatibility (less warnings). Height is properly calculated on the first bind and then it remembers the previous size, so it doesn't go into if (heightNotSet). (The code I linked is too old, I can't find the 23.2.0 version that has more conditions in the method, see your SDK's sources.)
According to the class documentation it's safe to put them there (they're used as fallback in some cases).
¯\_(ツ)_/¯ I really don't know. Unfortunately I don't have anytime to dig into this further.
The PercentLayout from bryanstern did fix the image jumping. I used Fresco before Glide and it had setAspectRatio method on the SimpleDraweeView which lets you have an image span 100% of the screen width and resize the height according to that width. I was struggling to find something similar for Glide and this is it.
Without TWiStErRob layoutParams.height = 0; the images would have random padding left and right and top and bottom when scrolling a RecyclerView. The same image could have different padding randomly.
Most helpful comment
If you happen to know the image's dimensions in advance, you can set the appropriate layout constraints with
PercentFrameLayoutfromcompile 'com.android.support:percent:23.0.0'.E.g. For a vertical staggered list manager
The view you'll inflate in
RecyclerView.Adapter#onCreateViewHolder