Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorating RecyclerView (with GridLayoutManager) to display divider between items

What's the best and easiest way to decorate RecyclerView to have such look & feel?

enter image description here

The main challenge here is having dividers only between items, but not between items and left/right borders of screen.

Any ideas?

like image 380
AlexKorovyansky Avatar asked Mar 19 '15 14:03

AlexKorovyansky


People also ask

How do I add a divider to my recycler view?

We have to create a default Divider using addItemDecoration() method with the RecyclerView instance, we need to pass the ItemDecoration(in this case it is DividerItemDecoration()) instance and the orientation of the LayoutManager(in this case it is vertical) of the recycler view.

What is DividerItemDecoration?

DividerItemDecoration is a RecyclerView. ItemDecoration that can be used as a divider between items of a LinearLayoutManager . It supports both HORIZONTAL and VERTICAL orientations.


2 Answers

I don't know why do you need that, but this UI is quite easy to implement with RecyclerView decorator.

<!--Integer Value that number of column in RecyclerView--> <integer name="photo_list_preview_columns">3</integer>  <!-- inter spacing between RecyclerView's Item--> <dimen name="photos_list_spacing">10dp</dimen> 

You can change photo_list_preview_columns and photos_list_spacing according to your needs.

mRecylerView.addItemDecoration(new ItemDecorationAlbumColumns(     getResources().getDimensionPixelSize(R.dimen.photos_list_spacing),      getResources().getInteger(R.integer.photo_list_preview_columns))); 

and decorator (needs some refatoring)

import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.View;  public class ItemDecorationAlbumColumns extends RecyclerView.ItemDecoration {      private int mSizeGridSpacingPx;     private int mGridSize;      private boolean mNeedLeftSpacing = false;      public ItemDecorationAlbumColumns(int gridSpacingPx, int gridSize) {         mSizeGridSpacingPx = gridSpacingPx;         mGridSize = gridSize;     }      @Override     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {         int frameWidth = (int) ((parent.getWidth() - (float) mSizeGridSpacingPx * (mGridSize - 1)) / mGridSize);         int padding = parent.getWidth() / mGridSize - frameWidth;         int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();         if (itemPosition < mGridSize) {             outRect.top = 0;         } else {             outRect.top = mSizeGridSpacingPx;         }         if (itemPosition % mGridSize == 0) {             outRect.left = 0;             outRect.right = padding;             mNeedLeftSpacing = true;         } else if ((itemPosition + 1) % mGridSize == 0) {             mNeedLeftSpacing = false;             outRect.right = 0;             outRect.left = padding;         } else if (mNeedLeftSpacing) {             mNeedLeftSpacing = false;             outRect.left = mSizeGridSpacingPx - padding;             if ((itemPosition + 2) % mGridSize == 0) {                 outRect.right = mSizeGridSpacingPx - padding;             } else {                 outRect.right = mSizeGridSpacingPx / 2;             }         } else if ((itemPosition + 2) % mGridSize == 0) {             mNeedLeftSpacing = false;             outRect.left = mSizeGridSpacingPx / 2;             outRect.right = mSizeGridSpacingPx - padding;         } else {             mNeedLeftSpacing = false;             outRect.left = mSizeGridSpacingPx / 2;             outRect.right = mSizeGridSpacingPx / 2;         }         outRect.bottom = 0;     } } 

enter image description hereenter image description here

like image 86
Dmitry L. Avatar answered Oct 05 '22 19:10

Dmitry L.


Here's a simpler and more user-friendly implementation:

public class MediaSpaceDecoration extends RecyclerView.ItemDecoration {     private final int spacing;     private final List<Integer> allowedViewTypes = Arrays.asList(             R.layout.item_image,             R.layout.item_blur);      public MediaSpaceDecoration(int spacing) {         this.spacing = spacing;     }      @Override     public void getItemOffsets(Rect outRect,                                View view,                                RecyclerView parent,                                RecyclerView.State state) {         final int position = parent.getChildAdapterPosition(view);         if (!isMedia(parent, position)) {             return;         }          final int totalSpanCount = getTotalSpanCount(parent);         int spanSize = getItemSpanSize(parent, position);         if (totalSpanCount == spanSize) {             return;         }          outRect.top = isInTheFirstRow(position, totalSpanCount) ? 0 : spacing;         outRect.left = isFirstInRow(position, totalSpanCount) ? 0 : spacing / 2;         outRect.right = isLastInRow(position, totalSpanCount) ? 0 : spacing / 2;         outRect.bottom = 0; // don't need     }      private boolean isInTheFirstRow(int position, int spanCount) {         return position < spanCount;     }      private boolean isFirstInRow(int position, int spanCount) {         return position % spanCount == 0;     }      private boolean isLastInRow(int position, int spanCount) {         return isFirstInRow(position + 1, spanCount);     }      private int getTotalSpanCount(RecyclerView parent) {         final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();         return layoutManager instanceof GridLayoutManager             ? ((GridLayoutManager) layoutManager).getSpanCount()             : 1;     }      private int getItemSpanSize(RecyclerView parent, int position) {         final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();         return layoutManager instanceof GridLayoutManager             ? ((GridLayoutManager) layoutManager).getSpanSizeLookup().getSpanSize(position)             : 1;     }      private boolean isMedia(RecyclerView parent, int viewPosition) {         final RecyclerView.Adapter adapter = parent.getAdapter();         final int viewType = adapter.getItemViewType(viewPosition);         return allowedViewTypes.contains(viewType);     } } 

I also check before setting the outRect because I have various spanSizes for each viewType and I need to add an extra middle-space only for allowedViewTypes. You can easily remove that verification and the code would be even simpler. It looks like this for me: GridLayout with a different spanSize for each viewType

like image 31
Nikolay Kulachenko Avatar answered Oct 05 '22 20:10

Nikolay Kulachenko