Last active
October 30, 2018 14:33
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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