Skip to content

Instantly share code, notes, and snippets.

@BenDLH
Last active October 30, 2018 14:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save BenDLH/41944fb884d308d9aae6d78aee87ce9f to your computer and use it in GitHub Desktop.
Save BenDLH/41944fb884d308d9aae6d78aee87ce9f to your computer and use it in GitHub Desktop.
Item decoration to add padding vertically and horizontally to RecyclerViews using Linear and Grid layout managers.
//
// Created by Ben on 28/09/2016.
// Copyright (c) 2016 SHAPE A/S. All rights reserved.
//
public class PaddingItemDecoration extends RecyclerView.ItemDecoration {
private final Context _context;
private Resources _resources;
private Paint _paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Rect rect = new Rect();
private final int _verticalPaddingPixels;
private final int _horizontalPaddingPixels;
private final boolean _externalPadding;
private int _colorResId = -1;
private int _drawableResId = -1;
private Drawable _drawable;
public PaddingItemDecoration(Context context, @DimenRes int paddingDimenRes) {
_context = context;
_verticalPaddingPixels = _horizontalPaddingPixels = (int) _context.getResources().getDimension(paddingDimenRes);
_externalPadding = false;
}
public PaddingItemDecoration(Context context, @DimenRes int paddingDimenRes, boolean externalPadding) {
_context = context;
_verticalPaddingPixels = _horizontalPaddingPixels = (int) _context.getResources().getDimension(paddingDimenRes);
_externalPadding = externalPadding;
}
public PaddingItemDecoration(Context context, @DimenRes int verticalPaddingDimenRes, @DimenRes int horizontalPaddingDimenRes) {
_context = context;
_verticalPaddingPixels = (int) _context.getResources().getDimension(verticalPaddingDimenRes);
_horizontalPaddingPixels = (int) _context.getResources().getDimension(horizontalPaddingDimenRes);
_externalPadding = false;
}
public PaddingItemDecoration(Context context, @DimenRes int verticalPaddingDimenRes, @DimenRes int horizontalPaddingDimenRes, boolean externalPadding) {
_context = context;
_verticalPaddingPixels = (int) _context.getResources().getDimension(verticalPaddingDimenRes);
_horizontalPaddingPixels = (int) _context.getResources().getDimension(horizontalPaddingDimenRes);
_externalPadding = externalPadding;
}
public void setItemBackgroundColorRes(@ColorRes int colorResId) {
_colorResId = colorResId;
}
public void setItemBackgroundDrawableRes(@DrawableRes int drawableResId) {
_drawableResId = drawableResId;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
// GridLayoutManager is a subclass of LinearLayoutManager, so we need to check for it first
if (parent.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
if (isVerticalOrientation(layoutManager)) { // Vertical grid
if (_externalPadding) {
outRect.top = _verticalPaddingPixels;
outRect.right = _horizontalPaddingPixels;
if (isFullSpanItem(layoutManager, view) || isStartSpanEdgeItem(layoutManager, view)) {
outRect.left = _horizontalPaddingPixels;
}
} else {
if (!isFirstSpanItem(parent, parent.getLayoutManager(), view)) {
outRect.top = _verticalPaddingPixels;
}
if (!isFullSpanItem(layoutManager, view) && !isStartSpanEdgeItem(layoutManager, view)) {
outRect.left = _horizontalPaddingPixels;
}
}
} else { // Horizontal grid
if (_externalPadding) {
outRect.left = _verticalPaddingPixels;
outRect.bottom = _horizontalPaddingPixels;
if (isFullSpanItem(layoutManager, view) || isStartSpanEdgeItem(layoutManager, view)) {
outRect.top = _horizontalPaddingPixels;
}
} else {
outRect.left = _verticalPaddingPixels;
if (isLastItem(parent, view)) {
outRect.right = _verticalPaddingPixels;
}
if (!isFullSpanItem(layoutManager, view) && !isStartSpanEdgeItem(layoutManager, view)) {
outRect.bottom = _horizontalPaddingPixels;
}
}
}
} else if (parent.getLayoutManager() instanceof LinearLayoutManager) { // (Vertical) list
if (_externalPadding) {
outRect.top = _verticalPaddingPixels;
// We want bottom padding on the bottom list item
if (isLastItem(parent, view)) {
outRect.bottom = _verticalPaddingPixels;
}
} else {
if (!isFirstSpanItem(parent, parent.getLayoutManager(), view)) {
outRect.top = _verticalPaddingPixels;
}
}
}
}
@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
super.onDraw(canvas, parent, state);
if (_colorResId == -1 && _drawableResId == -1) return;
if (_resources == null) _resources = _context.getResources();
int childCount = parent.getChildCount();
for (int index = 0; index < childCount; index++) {
View child = parent.getChildAt(index);
if (child == null) continue;
getItemOffsets(rect, child, parent, state);
if (_drawableResId != -1) {
if (_drawable == null) _drawable = _resources.getDrawable(_drawableResId);
_drawable.setBounds(parent.getLeft() + parent.getPaddingLeft(),
child.getTop() - rect.top,
parent.getRight() + parent.getPaddingRight(),
child.getBottom() + rect.bottom);
_drawable.draw(canvas);
} else if (_colorResId != -1) {
_paint.setColor(parent.getContext().getResources().getColor(_colorResId));
canvas.drawRect(parent.getLeft() + parent.getPaddingLeft(),
child.getTop() - rect.top,
parent.getRight() + parent.getPaddingRight(),
child.getBottom() + rect.bottom,
_paint);
}
}
}
private boolean isStartSpanEdgeItem(GridLayoutManager layoutManager, View view) {
int itemPosition = layoutManager.getPosition(view);
int currentSpanIndex = 0;
int totalSpanCount = layoutManager.getSpanCount();
for (int index = 0; index < itemPosition; index++) {
currentSpanIndex += totalSpanCount - layoutManager.getSpanSizeLookup().getSpanSize(index);
currentSpanIndex = currentSpanIndex % totalSpanCount;
}
return currentSpanIndex == 0;
}
private boolean isFirstSpanItem(RecyclerView recyclerView, RecyclerView.LayoutManager layoutManager, View itemView) {
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
return gridLayoutManager.getSpanSizeLookup().getSpanGroupIndex(recyclerView.getChildAdapterPosition(itemView), gridLayoutManager.getSpanCount()) == 0;
}
return recyclerView.getChildAdapterPosition(itemView) == 0;
}
private boolean isLastItem(RecyclerView recyclerView, View itemView) {
return recyclerView.getChildAdapterPosition(itemView) == recyclerView.getAdapter().getItemCount();
}
private boolean isVerticalOrientation(LinearLayoutManager layoutManager) {
return layoutManager.getOrientation() == LinearLayoutManager.VERTICAL;
}
private boolean isFullSpanItem(GridLayoutManager gridLayoutManager, View itemView) {
return gridLayoutManager.getSpanSizeLookup().getSpanSize(gridLayoutManager.getPosition(itemView)) == gridLayoutManager.getSpanCount();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment