Search code examples
androidandroid-recyclerviewandroid-constraintlayoutandroid-gridlayoutitem-decoration

RecyclerView’s ItemDecoration breaks items layout built with ConstraintLayout


I’m trying to build this layout - just two columns grid with images and text below images.

Mockup

I want to build this using RecyclerView, GridLayoutManager and ItemDecoration for spacing between items. 

Here’s what I get as a result, as you can see text below right images is shifted to the bottom.

Results

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);

        GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
        recyclerView.setLayoutManager(layoutManager);

        recyclerView.addItemDecoration(new SpacesItemDecoration());

        Adapter adapter = new Adapter();
        recyclerView.setAdapter(adapter);
    }
}

SpacesItemDecoration

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {

    @Override
    public void getItemOffsets(Rect outRect, View view,
                               RecyclerView parent, RecyclerView.State state) {
        outRect.bottom = 20;

        if (parent.getChildLayoutPosition(view) % 2 == 0) {
            outRect.right = 20;
        } else {
            outRect.right = 0;
        }
    }
}

item.xml

<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#DDDDDD"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="centerCrop"
        app:layout_constraintDimensionRatio="h,4:5"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/text_view"
        app:layout_constraintVertical_chainStyle="packed" />

    <TextView
        android:id="@+id/text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:textStyle="bold"
        android:gravity="center"
        app:layout_constraintTop_toBottomOf="@+id/image_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

You can also clone project from GitHub


Solution

  • From the screen shot you posted, it looks like the images on the right are larger than the images on the left and that is what pushes the text down on the right. This may be caused by how SpacesItemDecoration defines the insets. Try changing the left/right insets to balance the views out.

    SpacesItemDecoration

    public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    
        @Override
        public void getItemOffsets(Rect outRect, View view,
                                   RecyclerView parent, RecyclerView.State state) {
            outRect.bottom = 20;
    
            if (parent.getChildLayoutPosition(view) % 2 == 0) {
                outRect.right = 10; // Pad on the right for left-hand side
            } else {
                outRect.left = 10; // Pad on the left for right-hand side
            }
        }
    }