package com.github.jdsjlzx.ItemDecoration; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import com.github.jdsjlzx.recyclerview.LuRecyclerViewAdapter; /** * Adds spaces (between) between Item views. * * Supports GridLayoutManager and LinearLayoutManager. Extend this class and override the * {@link #getSpanLookup(View, RecyclerView)} method to support other * LayoutManagers. * * Currently only supports LayoutManagers in VERTICAL orientation. */ public class LuSpacesItemDecoration extends RecyclerView.ItemDecoration { private final int itemSplitMarginEven; private final int itemSplitMarginLarge; private final int itemSplitMarginSmall; private final int verticalSpacing; private Paint mPaint; public static LuSpacesItemDecoration newInstance(int horizontalSpacing, int verticalSpacing, int spanCount, int color) { int maxNumberOfSpaces = spanCount - 1; int totalSpaceToSplitBetweenItems = maxNumberOfSpaces * horizontalSpacing; int itemSplitMarginEven = (int) (0.5f * horizontalSpacing); int itemSplitMarginLarge = totalSpaceToSplitBetweenItems / spanCount; int itemSplitMarginSmall = horizontalSpacing - itemSplitMarginLarge; return new LuSpacesItemDecoration(itemSplitMarginEven, itemSplitMarginLarge, itemSplitMarginSmall, verticalSpacing, color); } private LuSpacesItemDecoration(int itemSplitMarginEven, int itemSplitMarginLarge, int itemSplitMarginSmall, int verticalSpacing, int color) { this.itemSplitMarginEven = itemSplitMarginEven; this.itemSplitMarginLarge = itemSplitMarginLarge; this.itemSplitMarginSmall = itemSplitMarginSmall; this.verticalSpacing = verticalSpacing; mPaint = new Paint(); mPaint.setColor(color); } /** * {@inheritDoc} */ @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { RecyclerView.Adapter adapter = parent.getAdapter(); LuRecyclerViewAdapter LuRecyclerViewAdapter; if (adapter instanceof LuRecyclerViewAdapter) { LuRecyclerViewAdapter = (LuRecyclerViewAdapter) adapter; } else { throw new RuntimeException("the adapter must be LuRecyclerViewAdapter"); } drawHorizontal(c,parent,LuRecyclerViewAdapter); drawVertical(c,parent,LuRecyclerViewAdapter); } public void drawHorizontal(Canvas c, RecyclerView parent,LuRecyclerViewAdapter adapter) { int count = parent.getChildCount(); for (int i = 0; i < count; i++) { final View child = parent.getChildAt(i); final int top = child.getBottom(); final int bottom = top + verticalSpacing; int left = child.getLeft() ; int right = child.getRight(); int position = parent.getChildAdapterPosition(child); c.save(); if (adapter. isHeader(position) || adapter.isFooter(position)) { c.drawRect(0, 0, 0, 0, mPaint); }else { c.drawRect(left, top, right, bottom, mPaint); } c.restore(); } } public void drawVertical(Canvas c, RecyclerView parent,LuRecyclerViewAdapter adapter) { int count = parent.getChildCount(); for (int i = 0; i < count; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); final int top = child.getTop(); //final int bottom = child.getBottom() + params.bottomMargin; final int bottom = child.getBottom() + verticalSpacing; //这里使用verticalSpacing 代替 params.bottomMargin final int left = child.getRight() + params.rightMargin; final int right = left + itemSplitMarginEven*2; int position = parent.getChildAdapterPosition(child); c.save(); if (adapter. isHeader(position) || adapter.isFooter(position)) { c.drawRect(0, 0, 0, 0, mPaint); }else { c.drawRect(left, top, right, bottom, mPaint); } c.restore(); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { RecyclerView.Adapter adapter = parent.getAdapter(); LuRecyclerViewAdapter LuRecyclerViewAdapter; if (adapter instanceof LuRecyclerViewAdapter) { LuRecyclerViewAdapter = (LuRecyclerViewAdapter) adapter; } else { throw new RuntimeException("the adapter must be LuRecyclerViewAdapter"); } RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); int itemPosition = layoutParams.getViewLayoutPosition(); int childCount = parent.getAdapter().getItemCount(); SpanLookup spanLookup = getSpanLookup(view, parent); applyItemHorizontalOffsets(spanLookup, itemPosition, outRect); applyItemVerticalOffsets(outRect, itemPosition, childCount, spanLookup.getSpanCount(), spanLookup,LuRecyclerViewAdapter); } protected SpanLookup getSpanLookup(View view, RecyclerView parent) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { return SpanLookupFactory.gridLayoutSpanLookup((GridLayoutManager) layoutManager); } return SpanLookupFactory.singleSpan(); } private void applyItemVerticalOffsets(Rect outRect, int itemPosition, int childCount, int spanCount, SpanLookup spanLookup,LuRecyclerViewAdapter adapter) { outRect.top = getItemTopSpacing(spanLookup, verticalSpacing, itemPosition, spanCount, childCount,adapter); outRect.bottom = getItemBottomSpacing(spanLookup, verticalSpacing, itemPosition, childCount,adapter); } private void applyItemHorizontalOffsets(SpanLookup spanLookup, int itemPosition, Rect offsets) { if (itemIsFullSpan(spanLookup, itemPosition)) { offsets.left = 0; offsets.right = 0; return; } if (itemStartsAtTheLeftEdge(spanLookup, itemPosition)) { offsets.left = 0; offsets.right = itemSplitMarginLarge; return; } if (itemEndsAtTheRightEdge(spanLookup, itemPosition)) { offsets.left = itemSplitMarginLarge; offsets.right = 0; return; } if (itemIsNextToAnItemThatStartsOnTheLeftEdge(spanLookup, itemPosition)) { offsets.left = itemSplitMarginSmall; } else { offsets.left = itemSplitMarginEven; } if (itemIsNextToAnItemThatEndsOnTheRightEdge(spanLookup, itemPosition)) { offsets.right = itemSplitMarginSmall; } else { offsets.right = itemSplitMarginEven; } } private static boolean itemIsNextToAnItemThatStartsOnTheLeftEdge(SpanLookup spanLookup, int itemPosition) { return !itemStartsAtTheLeftEdge(spanLookup, itemPosition) && itemStartsAtTheLeftEdge(spanLookup, itemPosition - 1); } private static boolean itemIsNextToAnItemThatEndsOnTheRightEdge(SpanLookup spanLookup, int itemPosition) { return !itemEndsAtTheRightEdge(spanLookup, itemPosition) && itemEndsAtTheRightEdge(spanLookup, itemPosition + 1); } private static boolean itemIsFullSpan(SpanLookup spanLookup, int itemPosition) { return itemStartsAtTheLeftEdge(spanLookup, itemPosition) && itemEndsAtTheRightEdge(spanLookup, itemPosition); } private static boolean itemStartsAtTheLeftEdge(SpanLookup spanLookup, int itemPosition) { return spanLookup.getSpanIndex(itemPosition) == 0; } private static boolean itemEndsAtTheRightEdge(SpanLookup spanLookup, int itemPosition) { return spanLookup.getSpanIndex(itemPosition) + spanLookup.getSpanSize(itemPosition) == spanLookup.getSpanCount(); } private static int getItemTopSpacing(SpanLookup spanLookup, int verticalSpacing, int itemPosition, int spanCount, int childCount, LuRecyclerViewAdapter adapter) { if(adapter.isHeader(itemPosition) || adapter.isFooter(itemPosition)) { return 0; } else { if (itemIsOnTheTopRow(spanLookup, itemPosition, spanCount, childCount)) { return 0; } else { return (int) (.5f * verticalSpacing); } } } private static boolean itemIsOnTheTopRow(SpanLookup spanLookup, int itemPosition, int spanCount, int childCount) { int latestCheckedPosition = 0; for (int i = 0; i < childCount; i++) { latestCheckedPosition = i; int spanEndIndex = spanLookup.getSpanIndex(i) + spanLookup.getSpanSize(i) - 1; if (spanEndIndex == spanCount - 1) { break; } } return itemPosition <= latestCheckedPosition; } private static int getItemBottomSpacing(SpanLookup spanLookup, int verticalSpacing, int itemPosition, int childCount, LuRecyclerViewAdapter adapter) { if(adapter.isHeader(itemPosition) || adapter.isFooter(itemPosition)) { return 0; } else { if (itemIsOnTheBottomRow(spanLookup, itemPosition, childCount)) { return 0; } else { return (int) (.5f * verticalSpacing); } } } private static boolean itemIsOnTheBottomRow(SpanLookup spanLookup, int itemPosition, int childCount) { int latestCheckedPosition = 0; for (int i = childCount - 1; i >= 0; i--) { latestCheckedPosition = i; int spanIndex = spanLookup.getSpanIndex(i); if (spanIndex == 0) { break; } } return itemPosition >= latestCheckedPosition; } }