What's the best and easiest way to decorate RecyclerView to have such look & feel?
The main challenge here is having dividers only between items, but not between items and left/right borders of screen.
Any ideas?
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.
DividerItemDecoration is a RecyclerView. ItemDecoration that can be used as a divider between items of a LinearLayoutManager . It supports both HORIZONTAL and VERTICAL orientations.
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; } }
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 spanSize
s 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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With