Apply offset to GridLayout items and preserve equal size among all items
Asked Answered
M

2

10

I want to create a space between items in the grid. The items should all have equal width/height.

What I've tried:

Create a GridLayoutOffsetDecorator that applies an offset to all grid items:

class GridLayoutOffsetDecorator(var offset: Int) : RecyclerView.ItemDecoration() {

    override fun getItemOffsets(
            outRect: Rect,
            view: View,
            parent: RecyclerView,
            state: RecyclerView.State?) {

        super.getItemOffsets(outRect, view, parent, state)

        outRect.set(offset, offset, offset, offset)
    }
}

Having an offset of 8dp creates a 16dp space between the items. So we still have to apply 8dp of padding to the outer edges:

<android.support.v7.widget.RecyclerView
        android:id="@+id/productList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:padding="8dp" />

The result is:

enter image description here

Problem: the items are not equal in size:

enter image description here

You notice a slight difference in height when you look at the blue line. This difference appears only after padding the recyclerview. This padding seems to slightly resize some of the items. Do you guys have any experience with this problem? Any idea how this can be solved?


By removing the image from the items, the height difference disappears. This is how the image is set:

<SquareImageView
    android:id="@+id/image"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:scaleType="centerCrop"
    app:imageResource="@{product.image}" />

SquareImageView:

class SquareImageView : ImageView {

    constructor(context: Context) : super(context)
    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec)
    }
}

So the problem may be caused by the image itself.

Mochun answered 25/4, 2017 at 13:8 Comment(6)
Where do the differences in height occur? is there a difference in all your items, or is only the item at index 0 higher than all the others ?Rea
@Rea the height difference is in one or two items but never in all, the position of the effected items is randomMochun
My first guess was that maybe the ImageView, which looks like its set to center-crop, is causing some trouble. Does it occur on text-only items too?Rea
@Rea yes, image is set to center-crop. Just checked it out, it does not occur on text-only items. The image is the problem then...I update my question with some details regarding the imageMochun
Are you using Glide for image loading?Rea
@Rea picasso.Mochun
E
2

I had the same problem when working with GridLayoutManager. Solved it by setting width and height for image in adapter. Here's my solution, hope it help.

That's how I placed ImageView in my layout.

<LinearLayout
     android:id="@+id/layoutImageProduct"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:gravity="center"
     tools:minHeight="100dp"
     tools:minWidth="150dp">

       <ImageView
           android:id="@+id/imageProduct"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:scaleType="fitCenter"
           android:src="@drawable/placeholder_product"/>
</LinearLayout>

And then apply LayoutParams on parent layout and ImageView

//Setting View width/height
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.layoutImageProduct.getLayoutParams();
params.width = (int) ResourcesUtils.getColumnWidth(context);
params.height = ((int) (ResourcesUtils.getColumnWidth(context)));
holder.layoutImageProduct.setLayoutParams(params);

params = (LinearLayout.LayoutParams) holder.imageProduct.getLayoutParams();
params.width = (int) ResourcesUtils.getColumnWidth(context);
params.height = (int) ResourcesUtils.getColumnWidth(context);
holder.imageProduct.setLayoutParams(params);

Here's the getWidth method.

public static float getColumnWidth(Context context) {
        if (GRID_COLUMN_WIDTH == -1) {
            int screenWidth = getDisplayMetrics(context).widthPixels;
            float horizontalPadding = getDimensInPixel(context, R.dimen.activity_horizontal_margin);
            // NUM OF COLUMN = 2
            GRID_COLUMN_WIDTH = screenWidth / 2 - horizontalPadding * 2;
        }

        return GRID_COLUMN_WIDTH;
    }

See the screenshot, one with placeholder and one with image. One with placeholder and one with image.

Eskill answered 4/5, 2017 at 11:59 Comment(1)
Well thank you, a bit hacky but it will totally solve the problem.Mochun
C
1

Can you please try with imageview height as fixed.

Candycecandystriped answered 4/5, 2017 at 11:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.